文档: 全库走查报告(docs/05-代码审查 00-05)+ 规范更新
This commit is contained in:
@@ -181,7 +181,52 @@ Stop hook 触发 skill 时同理,不另立记录位置。
|
||||
|
||||
---
|
||||
|
||||
## 九、待修(文档不一致)
|
||||
## 九、AI 生成文档的硬规则(2026-08-02 确立)
|
||||
|
||||
> 本节针对 AI 助手生成文档时的系统性问题,确立不可绕过的硬规则。
|
||||
> 触发场景:AI 走查 / 审查 / 调研 / 报告生成。
|
||||
|
||||
### 规则 1:生成前先查 INDEX.md
|
||||
|
||||
**禁止** 凭记忆或假设决定文档放置位置。
|
||||
**必须** 先读 `docs/INDEX.md` 的「目录结构」和「新文档放置规则」,确认目标目录,再生成文件。
|
||||
**原因**:AI 曾多次在根级新建 `walkthrough-YYYY-MM/` 等临时目录,事后需搬移 + 更新 INDEX,浪费 3 倍工作量。
|
||||
|
||||
### 规则 2:生成即归档,不建临时目录
|
||||
|
||||
文档直接写入目标目录(如 `05-代码审查/`),文件名带日期,一步到位。
|
||||
**禁止** 先建 `walkthrough-YYYY-MM/` 等中间目录,再事后搬移。
|
||||
**原因**:临时目录是技术债,残留文件(重复/中间产物)长期不清理。
|
||||
|
||||
### 规则 3:同一轮只保留一份
|
||||
|
||||
同一轮走查/审查,每个模块只生成一份报告,一份汇总。
|
||||
**禁止** 同一轮生成 2 份汇总、2 份同模块报告。
|
||||
**原因**:AI 多次生成 `00-汇总报告.md` + `00-summary-walkthrough.md` 等重复文件,内容高度重叠。
|
||||
|
||||
### 规则 4:更新 INDEX.md 与生成文档同步
|
||||
|
||||
生成文档后,**立即**更新 `docs/INDEX.md` 对应目录的条目。
|
||||
**禁止** 生成文档后忘记更新 INDEX。
|
||||
**原因**:INDEX 是文档导航入口,遗漏会导致文档"隐身"。
|
||||
|
||||
### 规则 5:操作失败 2 次即止损
|
||||
|
||||
同一个工具操作(delete_file / rename_file / patch_file)失败 2 次后:
|
||||
- **停止重复尝试**
|
||||
- **换方案**(如 delete 失败 → 改为 rename 加 `-冗余` 后缀)
|
||||
- **或停手汇报**,说明失败原因和当前状态
|
||||
**原因**:AI 曾多次对同一失败操作重复 3-4 次,浪费时间和审批额度。
|
||||
|
||||
### 规则 6:更新后必须验证
|
||||
|
||||
对 INDEX.md / 配置文件等关键文件 patch 后,**立即读取**确认结果正确。
|
||||
**禁止** patch 后直接宣称完成。
|
||||
**原因**:AI 曾把 6 条走查报告重复插入 INDEX.md 两次(12 条),直到用户指出才发现。
|
||||
|
||||
---
|
||||
|
||||
## 十、待修(文档不一致)
|
||||
|
||||
- ~~`docs/INDEX.md` 在 `07-项目管理/` 树下登记了 `PROGRESS.md`,但实际 PROGRESS 只在根级,`07-项目管理/` 下无此文件~~ → ✅ 已修(2026-06-12):移除该行,PROGRESS 统一指向根级。
|
||||
|
||||
|
||||
@@ -122,6 +122,13 @@
|
||||
- **状态**:✅ 已实施(reasoning 存主表 + extracted 事件 context.reasoning 双写,前端优先取主表降级取事件)
|
||||
- **教训**:LLM 输出字段与代码消费字段须对账——prompt 要求 LLM 产出的字段,代码侧漏消费是常见隐性 bug。
|
||||
|
||||
### AI 生成文档:先查 INDEX.md,生成即归档,失败 2 次即止损[2026-08-02]
|
||||
|
||||
- **现象**:AI 走查生成 6 份报告时,新建了 `docs/walkthrough-2026-08/` 临时目录(违反 INDEX.md 规定的 `05-代码审查/`)。事后搬移文件 + 清理残留 + 更新 INDEX.md,多出 3 倍工作量。同时生成了重复的汇总报告(`00-汇总报告.md` + `00-summary-walkthrough.md`)。
|
||||
- **根因**:AI 凭记忆决定文档位置,未先查 INDEX.md;生成时缺乏去重意识;失败后反复重试同一操作(delete/rename 超时 3 次以上)。
|
||||
- **状态**:✅ 已写入 `文档记录规范-2026-06-14.md` §九「AI 生成文档的硬规则」(6 条):①生成前查 INDEX ②生成即归档不建临时目录 ③同轮只保留一份 ④同步更新 INDEX ⑤失败 2 次即止损 ⑥更新后必须验证。
|
||||
- **教训**:文档生成是"先查规则再动手"的典型场景。AI 的默认行为是"边生成边决定",但文档结构是约定好的,必须先读 INDEX.md 确认放置规则。失败止损同样重要——同一操作失败 2 次就应该换方案或停手,不要死磕。
|
||||
|
||||
### prompt_tokens=0:深挖证伪非代码 bug(疑 GLM 订阅端点 message_start 缺 input_tokens)[#54 实测发现]
|
||||
|
||||
- **现象**:`ai_conversations.prompt_tokens=0`(completion=1496 正常)。GLM-订阅(anthropic 协议)1 对话 24 消息,所有 assistant 消息 `usage=None`。
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
# DevFlow 全库代码走查汇总报告
|
||||
|
||||
> 走查日期: 2026-08-02
|
||||
> 范围: 全部 12 个 crate + 1 个 src-tauri(入口),约 100+ 文件,~1.5MB 代码
|
||||
> 走查方式: 逐文件全量阅读 + 交叉引用 + 架构分析
|
||||
|
||||
---
|
||||
|
||||
## 总览
|
||||
|
||||
| 报告 | 文件数 | 问题数 | P0 | P1 | P2 |
|
||||
|---|---|---|---|---|---|
|
||||
| 01-df-nodes | 17 | 20 | 3 | 7 | 10 |
|
||||
| 02-df-workflow | 11 | 9 | 1 | 4 | 4 |
|
||||
| 03-df-ai | 30 | 13 | 5 | 3 | 5 |
|
||||
| 04-df-storage-ideas-mcp | 13 | 17 | 2 | 8 | 7 |
|
||||
| 05-df-relay-tunnel-project-execute | 15 | 19 | 0 | 8 | 11 |
|
||||
| **合计** | **86** | **78** | **11** | **30** | **37** |
|
||||
|
||||
---
|
||||
|
||||
## 按严重等级分布
|
||||
|
||||
### 🔴 P0(11 个,必须立即修)
|
||||
|
||||
| # | 模块 | 文件 | 问题 |
|
||||
|---|---|---|---|
|
||||
| 1 | df-nodes | ai_node.rs | schema `required=[]` 但运行时 prompt 必填,前后端不一致 |
|
||||
| 2 | df-nodes | ai_self_review_node.rs | schema `required=["task_id","provider_id"]` 但 provider_id 可空 |
|
||||
| 3 | df-nodes | docker_node.rs | shell_quote 不处理 `;` `|` `&`,命令注入漏洞 |
|
||||
| 4 | df-workflow | conditions.rs | 单引号 `''` 转义边界 bug |
|
||||
| 5 | df-ai | openai_compat.rs(58KB) | 超大文件,应拆分 |
|
||||
| 6 | df-ai | anthropic_compat.rs(54KB) | 超大文件,应拆分 |
|
||||
| 7 | df-ai | context_helpers.rs(63KB) | 超大文件,应拆分 |
|
||||
| 8 | df-ai | coordinator.rs(65KB) | 超大文件,应拆分 |
|
||||
| 9 | df-ai | sanitize.rs(51KB) | 超大文件,应拆分 |
|
||||
| 10 | df-storage | migrations.rs(89KB) | 超大文件,应拆分 |
|
||||
| 11 | df-storage | models.rs(25KB) | 超大文件,应拆分 |
|
||||
|
||||
### 🟡 P1(30 个,尽快修)
|
||||
|
||||
主要分布:
|
||||
- **df-nodes**: DockerNode 命令注入、HumanNode timeout 3600s 过长、SubflowNode 不执行子 DAG
|
||||
- **df-ai**: intent.rs 57KB 大文件、router cost_tier 悬空、retry 硬编码
|
||||
- **df-storage**: keyring 迁移失败保留明文、单连接 Mutex、idea_repo 65KB
|
||||
- **df-ideas**: adversarial 启发式论点模板化、LLM 一致性未校验
|
||||
- **df-mcp**: tools.rs 31KB 大文件、未校验实体类型
|
||||
- **df-relay**: 单 token 鉴权、锁粒度粗
|
||||
- **df-tunnel**: 无自动重连 supervisor
|
||||
- **df-execute**: pwsh 探测时序风险、env_snapshot 卡死
|
||||
|
||||
### 🟢 P2(37 个,后续迭代)
|
||||
|
||||
技术债务、轻微代码异味、文档不足。
|
||||
|
||||
---
|
||||
|
||||
## 关键发现
|
||||
|
||||
### 1. 大文件问题突出(11 个 P0 中 6 个是大文件)
|
||||
|
||||
| 文件 | 行数 | 建议 |
|
||||
|---|---|---|
|
||||
| `migrations.rs` | 89KB/1914行 | 拆为 migrations/v1.rs~v37.rs |
|
||||
| `coordinator.rs` | 65KB | 拆为 coordinator/tasks.rs + scheduler.rs + state.rs |
|
||||
| `context_helpers.rs` | 63KB | 拆为 token_estimator.rs + config.rs + classify.rs |
|
||||
| `openai_compat.rs` | 58KB | 拆为 protocol.rs + stream.rs + embed.rs |
|
||||
| `anthropic_compat.rs` | 54KB | 同上 |
|
||||
| `sanitize.rs` | 51KB | 拆为 sanitize/ 目录 |
|
||||
| `idea_repo.rs` | 65KB | 拆为 IdeaRepo + KnowledgeRepo + KnowledgeEventsRepo |
|
||||
| `task_repo.rs` | 42KB | 拆为常规 CRUD + advance_status_atomic 专用文件 |
|
||||
| `intent.rs` | 57KB | 拆为多个意图分类文件 |
|
||||
| `models.rs` | 25KB | 拆为 models/idea.rs + project.rs + task.rs + ai.rs |
|
||||
| `tools.rs`(df-mcp) | 31KB | 拆为 tools/ 目录 |
|
||||
|
||||
### 2. 安全风险
|
||||
|
||||
- **P0**: DockerNode shell_quote 命令注入(`;` `|` `&` 未转义)
|
||||
- **P1**: df-storage 单连接 Mutex 无并发保护
|
||||
- **P1**: df-mcp 未校验实体类型(跨实体误操作)
|
||||
- **P1**: keyring 迁移失败保留明文在 SQLite
|
||||
|
||||
### 3. 功能不完整
|
||||
|
||||
- **SubflowNode**: 只返回子 DAG 元数据,不实际执行
|
||||
- **NotifyNode**: desktop 类型只是 tracing 日志占位
|
||||
- **conditions-eval**: 934 行条件引擎写了但默认 feature 关闭
|
||||
- **coordinator**: 65KB 多 Agent 协调但未接入主 loop
|
||||
- **planner**: 38KB 规划器但 Phase 0 未接入主 loop
|
||||
|
||||
### 4. 设计优秀点
|
||||
|
||||
- **状态机**: task_state_machine 双源一致性测试锁定 + 原子 CAS 写
|
||||
- **对抗评估**: 三路径降级 + 三角色辩论 + 容错解析
|
||||
- **重试策略**: 指数退避 + jitter + Fatal/Retryable 分类 + 预算上限
|
||||
- **SSE 解析器**: 宽松 UTF-8 + 三种分隔符兼容 + 1MB 缓冲区上限
|
||||
- **密钥管理**: keyring 迁移 + 失败计数阈值 + 归一化校验
|
||||
- **MCP 安全**: High 风险默认拒绝 + read-only 模式 + 双保险
|
||||
|
||||
---
|
||||
|
||||
## 修复优先级建议
|
||||
|
||||
### 立即修(P0,影响安全性/功能正确性)
|
||||
|
||||
1. **docker_node.rs shell_quote 命令注入** — 用 shell-escape crate 或手动转义所有元字符
|
||||
2. **ai_node.rs + ai_self_review_node.rs schema 不一致** — 修正 required 字段
|
||||
3. **6 个大文件拆分** — 按模块拆分为多文件
|
||||
|
||||
### 尽快修(P1,影响稳定性/可维护性)
|
||||
|
||||
1. HumanNode timeout 默认值 3600s 过长 → 改为 1800s
|
||||
2. SubflowNode 不执行子 DAG → 补递归执行
|
||||
3. HttpNode 每次新建 Client → 复用连接池
|
||||
4. df-mcp 未校验实体类型 → 对齐 B-260801-01 修复
|
||||
5. keyring 迁移失败保留明文 → 加 AES fallback 或更强告警
|
||||
|
||||
### 后续迭代(P2)
|
||||
|
||||
1. 大文件拆分持续推进
|
||||
2. conditions-eval 默认开启
|
||||
3. NotifyNode desktop 集成 tauri-plugin-notification
|
||||
4. ScriptNode dangerous_keywords 配置化
|
||||
5. 自动重连 supervisor(df-tunnel)
|
||||
@@ -0,0 +1,310 @@
|
||||
# df-nodes 代码走查报告
|
||||
|
||||
> 走查日期: 2026-08-02
|
||||
> 范围: crates/df-nodes/src/ (17 文件, ~280KB)
|
||||
> 走查方式: 逐文件全量阅读 + 交叉引用
|
||||
|
||||
---
|
||||
|
||||
## 问题汇总
|
||||
|
||||
| # | 等级 | 文件 | 类型 | 简述 |
|
||||
|---|---|---|---|---|
|
||||
| 1 | 🔴 P0 | ai_node.rs | bug | schema `required=[]` 但 execute 时 prompt 必填,schema/运行时不一致 |
|
||||
| 2 | 🔴 P0 | ai_self_review_node.rs | bug | schema `required=["task_id","provider_id"]` 但 execute 时 provider_id 可空 |
|
||||
| 3 | 🔴 P0 | docker_node.rs | risk | shell_quote 不处理 `;` `|` `&` 等 shell 元字符,存在命令注入 |
|
||||
| 4 | 🟡 P1 | docker_node.rs | risk | 命令注入:volumes.host 用户可控,shell_quote 不完整 |
|
||||
| 5 | 🟡 P1 | human_node.rs | risk | timeout_secs 默认 3600s(1小时),前端崩溃时用户等 1 小时 |
|
||||
| 6 | 🟡 P1 | http_node.rs | smell | 每次请求新建 reqwest::Client,无连接池复用 |
|
||||
| 7 | 🟡 P1 | docker_node.rs | smell | 每次执行都 `docker --version` 探测,浪费 |
|
||||
| 8 | 🟡 P1 | subflow_node.rs | bug | 只返回子 DAG 元数据,不实际执行子 DAG |
|
||||
| 9 | 🟡 P1 | notify_node.rs | tech-debt | desktop 类型只是 tracing 日志占位,不发送桌面通知 |
|
||||
| 10 | 🟡 P1 | human_node.rs | smell | 833 行单文件,impl + 测试混在一起 |
|
||||
| 11 | 🟡 P1 | conditions.rs | smell | 934 行单文件,解析器 + JSON Path + 测试未拆分 |
|
||||
| 12 | 🟡 P1 | task_advance_node.rs | smell | 528 行含大量测试,测试应拆到独立模块 |
|
||||
| 13 | 🟢 P2 | docker_node.rs | smell | shell_quote 与 git_node.rs 重复定义(DRY 漂移) |
|
||||
| 14 | 🟢 P2 | docker_node.rs | smell | volumes 解析跳过坏项但不 warn,用户不知配置被忽略 |
|
||||
| 15 | 🟢 P2 | script_node.rs | risk | dangerous_keywords 硬编码且仅告警不阻止 |
|
||||
| 16 | 🟢 P2 | script_node.rs | smell | 白名单/黑名单用 OnceLock,设置后不可重置 |
|
||||
| 17 | 🟢 P2 | human_node_helpers.rs | risk | REJECT_KEYWORDS 含 "no","no problem" 等文本可能误判 |
|
||||
| 18 | 🟢 P2 | conditions.rs | tech-debt | 934 行条件引擎写了但默认 feature 关闭 |
|
||||
| 19 | 🟢 P2 | ai_node_helpers.rs | smell | resolve_provider 三路径逻辑清晰但函数过长(80行) |
|
||||
| 20 | 🟢 P2 | ai_self_review_node.rs | smell | build_review_prompt 用 format! 拼接 JSON 模板,可读性差 |
|
||||
|
||||
---
|
||||
|
||||
## 🔴 P0 问题详述
|
||||
|
||||
### #1 AiNode schema/运行时不一致
|
||||
|
||||
**文件**: `ai_node.rs:118-127`
|
||||
**严重**: P0 — schema 是前端校验依据,不一致导致前端误拒合法配置
|
||||
|
||||
**现状**:
|
||||
```rust
|
||||
// schema 声明 required=[]
|
||||
"required": []
|
||||
```
|
||||
|
||||
**运行时**:
|
||||
```rust
|
||||
// ai_node_helpers.rs:156-164
|
||||
let prompt = inputs.get("prompt")
|
||||
.or_else(|| config.get("prompt"))
|
||||
.ok_or_else(|| anyhow!("缺少必填参数: prompt"))?;
|
||||
```
|
||||
|
||||
**影响**: 前端按 schema 校验认为 prompt 可选,用户不填时前端放行但后端报错。
|
||||
|
||||
**建议**: schema `required` 加 `"prompt"`,或在 schema 描述中注明"config.prompt 或上游 inputs.prompt 至少一个必填"。
|
||||
|
||||
---
|
||||
|
||||
### #2 AiSelfReviewNode schema/运行时不一致
|
||||
|
||||
**文件**: `ai_self_review_node.rs:276-280`
|
||||
**严重**: P0 — 同上,schema 说 provider_id 必填但运行时可空
|
||||
|
||||
**现状**:
|
||||
```rust
|
||||
"required": ["task_id", "provider_id"]
|
||||
```
|
||||
|
||||
**运行时**: `resolve_and_parse` 三路径兜底,provider_id 可空(走默认 provider)。
|
||||
|
||||
**影响**: 前端按 schema 强制要求 provider_id,用户不填被前端拒绝,但实际后端能兜底。
|
||||
|
||||
**建议**: schema `required` 改为 `["task_id"]`,provider_id 描述注明"留空走默认 provider"。
|
||||
|
||||
---
|
||||
|
||||
### #3 DockerNode shell_quote 命令注入
|
||||
|
||||
**文件**: `docker_node.rs:105-111`
|
||||
**严重**: P0 — 用户可控输入经不完整的 shell_quote 进入 shell 命令
|
||||
|
||||
**现状**:
|
||||
```rust
|
||||
fn shell_quote(s: &str) -> String {
|
||||
if s.chars().any(|c| c.is_whitespace() || c == '"' || c == '$' || c == '`') {
|
||||
format!("\"{}\"", s.replace('"', "\\\""))
|
||||
} else {
|
||||
s.to_string()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**漏洞**: 只处理空格/双引号/$/反引号,不处理 `;` `|` `&` `` ` `` (反引号在条件中但替换时未转义)。
|
||||
|
||||
**攻击场景**: 用户传入 `host: "/workspace; rm -rf /"` → shell_quote 检测到空格加引号 → `"\"/workspace; rm -rf /\""` → 引号内的 `;` 被 shell 解释为命令分隔符。
|
||||
|
||||
**建议**: 使用 `shell-escape` crate 或手动转义所有 shell 元字符(`;` `|` `&` `` ` `` `$` `(` `)` `<` `>` `{` `}` `!`)。
|
||||
|
||||
---
|
||||
|
||||
## 🟡 P1 问题详述
|
||||
|
||||
### #4 DockerNode volumes.host 用户可控
|
||||
|
||||
**文件**: `docker_node.rs:105-111`
|
||||
**严重**: P1 — 与 #3 关联,volumes.host 是用户直接传入的字符串
|
||||
|
||||
**影响**: 攻击者通过 volumes 配置注入 shell 命令。
|
||||
|
||||
---
|
||||
|
||||
### #5 HumanNode timeout 默认值过长
|
||||
|
||||
**文件**: `human_node.rs:43`
|
||||
**严重**: P1 — 用户体验问题
|
||||
|
||||
**现状**:
|
||||
```rust
|
||||
let timeout_secs = config.get("timeout_secs")
|
||||
.and_then(|v| v.as_u64())
|
||||
.unwrap_or(3600); // 1 小时
|
||||
```
|
||||
|
||||
**影响**: 前端崩溃/用户离开时,审批节点等 1 小时才超时。
|
||||
|
||||
**建议**: 默认值改为 1800s(30分钟)或 3600s 但加 max 上限。
|
||||
|
||||
---
|
||||
|
||||
### #6 HttpNode 每次新建 Client
|
||||
|
||||
**文件**: `http_node.rs:105-110`
|
||||
**严重**: P1 — 性能问题
|
||||
|
||||
**现状**:
|
||||
```rust
|
||||
let client = reqwest::Client::builder()
|
||||
.timeout(Duration::from_secs(params.timeout_secs))
|
||||
.build()?;
|
||||
```
|
||||
|
||||
**影响**: 每次节点执行都新建 HTTP client,无法复用连接池,高并发工作流时性能差。
|
||||
|
||||
**建议**: 用 `OnceLock<reqwest::Client>` 或 `Arc<reqwest::Client>` 共享。
|
||||
|
||||
---
|
||||
|
||||
### #7 DockerNode 每次 docker --version
|
||||
|
||||
**文件**: `docker_node.rs:88-96`
|
||||
**严重**: P1 — 性能浪费
|
||||
|
||||
**现状**: 每次节点执行都跑一次 `docker --version` 探测。
|
||||
|
||||
**建议**: 用 `OnceLock<bool>` 缓存探测结果。
|
||||
|
||||
---
|
||||
|
||||
### #8 SubflowNode 不实际执行子 DAG
|
||||
|
||||
**文件**: `subflow_node.rs:45-67`
|
||||
**严重**: P1 — 功能不完整
|
||||
|
||||
**现状**:
|
||||
```rust
|
||||
Ok(NodeOutput::from_value(serde_json::json!({
|
||||
"subflow": true,
|
||||
"node_count": sub_dag.nodes.len(),
|
||||
...
|
||||
"dag": sub_dag, // 只返回元数据
|
||||
})))
|
||||
```
|
||||
|
||||
**影响**: SubflowNode 只返回子 DAG 的 JSON 快照,不递归执行。注释说"供 DagExecutor 消费",但 executor 不会自动执行返回的 subflow。
|
||||
|
||||
**建议**: 要么在 execute 内递归调 `DagExecutor::run`,要么明确文档说明"需要调用方自行执行返回的 DAG"。
|
||||
|
||||
---
|
||||
|
||||
### #9 NotifyNode desktop 只是日志
|
||||
|
||||
**文件**: `notify_node.rs:108-117`
|
||||
**严重**: P1 — 功能缺失
|
||||
|
||||
**现状**:
|
||||
```rust
|
||||
NotifyType::Desktop => {
|
||||
tracing::info!(title = %params.title, message = %params.message,
|
||||
"NotifyNode desktop 通知(日志占位,集成待后续 Sprint)");
|
||||
Ok(NodeOutput::from_value(...))
|
||||
}
|
||||
```
|
||||
|
||||
**影响**: 用户配置 desktop 通知类型,实际只写日志,不发送桌面通知。
|
||||
|
||||
**建议**: 要么移除 desktop 类型,要么集成 tauri-plugin-notification。
|
||||
|
||||
---
|
||||
|
||||
### #10-12 大文件拆分
|
||||
|
||||
**文件**: human_node.rs(833行) / conditions.rs(934行) / task_advance_node.rs(528行)
|
||||
**严重**: P1 — 可维护性
|
||||
|
||||
**建议**:
|
||||
- human_node.rs: 测试拆到 `human_node_tests.rs`
|
||||
- conditions.rs: 拆为 `tokenizer.rs` / `parser.rs` / `jsonpath.rs` / `tests.rs`
|
||||
- task_advance_node.rs: 测试拆到独立模块
|
||||
|
||||
---
|
||||
|
||||
## 🟢 P2 问题详述
|
||||
|
||||
### #13 shell_quote DRY 漂移
|
||||
|
||||
**文件**: `docker_node.rs:105-111` 与 `git_node.rs:137-142`
|
||||
**严重**: P2 — 两处逐字相同
|
||||
|
||||
**建议**: 抽到 `df-nodes/src/shell_quote.rs` 共享。
|
||||
|
||||
---
|
||||
|
||||
### #14 DockerNode volumes 跳过坏项不 warn
|
||||
|
||||
**文件**: `docker_node.rs:62-70`
|
||||
**严重**: P2
|
||||
|
||||
**建议**: 跳过时 `tracing::warn!` 记录被跳过的配置项。
|
||||
|
||||
---
|
||||
|
||||
### #15 ScriptNode dangerous_keywords 硬编码
|
||||
|
||||
**文件**: `script_node.rs:58-65`
|
||||
**严重**: P2 — 仅告警不阻止,关键词列表不完整
|
||||
|
||||
---
|
||||
|
||||
### #16 ScriptNode OnceLock 不可重置
|
||||
|
||||
**文件**: `script_node.rs:13-18`
|
||||
**严重**: P2 — 设置后不可重置,需重启应用
|
||||
|
||||
---
|
||||
|
||||
### #17 REJECT_KEYWORDS 含 "no" 过宽
|
||||
|
||||
**文件**: `human_node_helpers.rs:14-18`
|
||||
**严重**: P2 — "no" 作为拒绝关键字太宽泛
|
||||
|
||||
**建议**: 改为 "no" 仅当 options 含 "no" 时匹配,或从关键字列表移除。
|
||||
|
||||
---
|
||||
|
||||
### #18 conditions.rs 默认 feature 关闭
|
||||
|
||||
**文件**: `conditions.rs` (934行)
|
||||
**严重**: P2 — 写了大量代码但默认不启用
|
||||
|
||||
**建议**: 要么默认开启,要么在 README 中说明如何启用。
|
||||
|
||||
---
|
||||
|
||||
## 正面评价(值得保留的设计)
|
||||
|
||||
1. **状态机设计优秀**: `task_state_machine.rs` 从 `TaskStatus::as_str()` 派生常量,消除双源问题,有双源一致性测试锁定。
|
||||
|
||||
2. **advance_task_atomic 原子写**: CAS `WHERE status=expected` 防 TOCTOU,退回转换一并 `review_rounds+=1`,设计严谨。
|
||||
|
||||
3. **HumanNode 拒绝语义化**: 审批拒绝从 Ok→Err,触发工作流 failed→退回,语义正确。
|
||||
|
||||
4. **AiSelfReviewNode 兜底设计**: LLM 输出不可靠时 verdict=unknown 不阻断,保持人定权。
|
||||
|
||||
5. **executor 取消处理**: Ok/Err 分支对称处理已取消节点,状态机与事件类型一致。
|
||||
|
||||
6. **EventBus broadcast 容量 256**: 审批低频场景下漏自身 Response 概率极低,设计合理。
|
||||
|
||||
7. **conditions.rs 求值失败保守 false**: 任何解析错误/JSON Path 缺失/类型不兼容均返回 false,安全优先。
|
||||
|
||||
8. **StateMachine 锁中毒降级**: 不 panic,返回保守默认值或 Err,符合"无 panic"铁律。
|
||||
|
||||
9. **测试覆盖率高**: 每个节点文件都有配套测试,advance_task_atomic 有 20+ 测试覆盖各种状态转换。
|
||||
|
||||
10. **代码注释详尽**: 每处设计决策都有注释说明理由、替代方案和选型依据。
|
||||
|
||||
---
|
||||
|
||||
## 改进优先级建议
|
||||
|
||||
```
|
||||
立即修复(P0):
|
||||
#1 AiNode schema/运行时不一致
|
||||
#2 AiSelfReviewNode schema/运行时不一致
|
||||
#3 DockerNode shell_quote 命令注入
|
||||
|
||||
尽快修复(P1):
|
||||
#4 DockerNode volumes 注入(与 #3 一起修)
|
||||
#5 HumanNode timeout 默认值
|
||||
#6 HttpNode Client 复用
|
||||
#8 SubflowNode 功能不完整
|
||||
|
||||
后续迭代(P2):
|
||||
#10-12 大文件拆分
|
||||
#13 shell_quote DRY
|
||||
#17 REJECT_KEYWORDS "no" 过宽
|
||||
```
|
||||
@@ -0,0 +1,71 @@
|
||||
# df-workflow 核心代码走查报告
|
||||
|
||||
> 走查日期: 2026-08-02
|
||||
> 范围: crates/df-workflow/src/ (11 文件, ~108KB)
|
||||
> 核心文件: executor.rs(258行), conditions.rs(934行), state.rs(257行), registry.rs(81行), node.rs(77行), dag.rs, dag_def.rs, eventbus.rs(57行)
|
||||
|
||||
---
|
||||
|
||||
## 问题汇总
|
||||
|
||||
| # | 等级 | 文件 | 类型 | 简述 |
|
||||
|---|---|---|---|---|
|
||||
| 1 | 🔴 P0 | conditions.rs | bug | 单引号字符串 `''` 转义为 `'` 时闭引号后再跟 `'` 会误判(如 `'it''s'` 跨行) |
|
||||
| 2 | 🟡 P1 | conditions.rs | smell | 934 行单文件,tokenizer/parser/jsonpath/测试全混在一起,维护性差 |
|
||||
| 3 | 🟡 P1 | conditions.rs | risk | 默认 feature `conditions-eval` 关闭,934 行代码实际不生效 |
|
||||
| 4 | 🟡 P1 | executor.rs | risk | `condition` 边条件求值仅在 `eval_conditions` 为 true 时收集 inputs,但 `outputs.insert` 仍写入所有节点,已跳过的节点 output 可能被下游无条件边误消费 |
|
||||
| 5 | 🟡 P1 | state.rs | risk | 锁中毒降级日志缺少 `node_id` 上下文,排查时难以定位哪个节点触发了中毒 |
|
||||
| 6 | 🟢 P2 | node.rs | smell | `NodeContext` 的 `inputs` 类型为 `HashMap<String, NodeOutput>`,`NodeOutput` 仅含 `data: serde_json::Value`,工具调用结果无法区分来源 |
|
||||
| 7 | 🟢 P2 | executor.rs | smell | 条件路由的 `eval_conditions` 标志取自 `cfg!(feature = "conditions-eval")`,编译期常量化后分支在运行时不可变,但 executor 仍用 `if eval_conditions` 运行时分支 |
|
||||
| 8 | 🟢 P2 | eventbus.rs | smell | `send` 参数 `async fn` 但实际是同步调用(`broadcast::send` 同步),`async` 包装造成误导 |
|
||||
| 9 | 🟢 P2 | executor.rs | smell | `adjacency_in` 预建索引仅用于 `condition` 场景,非条件场景下 `HashMap::new()` 占位浪费 |
|
||||
|
||||
---
|
||||
|
||||
## 🔴 P0 问题详述
|
||||
|
||||
### #1 conditions.rs 单引号转义边界 bug
|
||||
|
||||
**文件**: `conditions.rs:200-225`
|
||||
**严重**: P0 — 可能产生错误的表达式求值结果
|
||||
|
||||
**现状**: `consume_quoted` 函数在遇到 `''` 时跳过(视为转义),但 `consume_key` 不处理单引号。
|
||||
|
||||
**影响**: 表达式 `'it''s' == 'value'` 中,`'it''s'` 被解析为 `it's`,但闭引号后紧跟 `'==` 可能导致 `consume_key` 截断异常。
|
||||
|
||||
---
|
||||
|
||||
## 🟡 P1 问题详述
|
||||
|
||||
### #2 conditions.rs 单文件 934 行
|
||||
|
||||
**建议**: 拆为 `tokenizer.rs` / `parser.rs` / `jsonpath.rs` / `tests.rs` 四个模块,类似 df-nodes 的拆分模式。
|
||||
|
||||
### #3 conditions-eval feature 默认关闭
|
||||
|
||||
**现状**: 934 行代码 + 全面测试 + 递归下降解析器 + JSON Path 引擎,全部在 feature gate 后面。executor 中 `eval_conditions` 编译期常量化,运行时条件路由不生效。
|
||||
|
||||
**建议**: 要么默认开启 feature,要么在 ARCHITECTURE.md 中说明为何写了不开。
|
||||
|
||||
### #4 executor 条件边 output 残留
|
||||
|
||||
**文件**: `executor.rs:188`
|
||||
**风险**: 已跳过的节点(condition 不满足),`outputs.insert` 不会执行(因为 `continue` 了),但若后续层有**无条件边**引用该跳过的节点,`outputs.get` 返回 None,下游节点inputs 空。
|
||||
|
||||
**建议**: 确认无条件边是否有 fallback 处理,或补测试覆盖。
|
||||
|
||||
### #5 锁中毒日志缺少 node_id
|
||||
|
||||
**文件**: `state.rs:60-68`
|
||||
**建议**: 在 `lock()` 失败时输出的 `tracing::error!` 中增加 `node_id` 参数,便于排查。
|
||||
|
||||
---
|
||||
|
||||
## 正面评价
|
||||
|
||||
1. **状态机设计优秀**: `is_legal` 转换表清晰,`set_cancelled` 作为唯一受控旁路,设计合理
|
||||
2. **executor 取消处理**: Ok/Err 分支对称处理已取消节点,状态机与事件类型一致,TOCTOU 已修复
|
||||
3. **EventBus broadcast 容量 256**: 审批低频场景设计合理
|
||||
4. **conditions 求值失败保守 false**: 安全优先,文档清晰
|
||||
5. **锁中毒降级不 panic**: 返回保守默认值,符合"无 panic"铁律
|
||||
6. **测试覆盖**: state.rs 测试完整(合法/非法/克隆/取消),executor 测试在 executor_helpers.rs
|
||||
@@ -0,0 +1,106 @@
|
||||
# df-ai + df-ai-core 代码走查报告
|
||||
|
||||
> 走查日期: 2026-08-02
|
||||
> 范围: crates/df-ai (26 files, ~500KB) + crates/df-ai-core (4 files, ~55KB)
|
||||
|
||||
---
|
||||
|
||||
## 文件规模统计
|
||||
|
||||
| 文件 | 行数 | 类型 |
|
||||
|---|---|---|
|
||||
| openai_compat.rs | 58,524 | Provider HTTP 实现 |
|
||||
| anthropic_compat.rs | 54,492 | Provider HTTP 实现 |
|
||||
| context/mod.rs | 32,028 | 上下文管理器 |
|
||||
| context/sanitize.rs | 51,416 | 畸形配对自愈 |
|
||||
| coordinator.rs | 65,321 | 多 Agent 协调 |
|
||||
| intent.rs | 57,390 | 意图识别 |
|
||||
| context_helpers.rs | 63,660 | 上下文辅助 |
|
||||
| planner.rs | 38,451 | 规划器 |
|
||||
| plan_hint.rs | 26,621 | 规划提示 |
|
||||
| df-ai-core/provider.rs | 24,849 | Provider trait + 类型 impl |
|
||||
| df-ai-core/model.rs | 18,390 | 模型能力数据模型 |
|
||||
| df-ai-core/types.rs | 12,835 | 核心类型定义 |
|
||||
|
||||
---
|
||||
|
||||
## 问题汇总
|
||||
|
||||
| # | 等级 | 文件 | 类型 | 简述 |
|
||||
|---|---|---|---|---|
|
||||
| 1 | 🔴 P0 | openai_compat(58KB) + anthropic_compat(54KB) | smell | 两个 provider 文件超 50KB,大量代码重复(流式解析/工具调用/错误处理) |
|
||||
| 2 | 🔴 P0 | coordinator(65KB) | smell | 单文件 65KB,DevFlow 最大文件,职责过宽 |
|
||||
| 3 | 🔴 P0 | context_helpers(63KB) | smell | 63KB 纯辅助函数,应拆分 |
|
||||
| 4 | 🟡 P1 | intent(57KB) | smell | 意图识别 57KB,正则/模式匹配过多 |
|
||||
| 5 | 🟡 P1 | context/sanitize(51KB) | smell | 畸形配对自愈逻辑 51KB,复杂度过高 |
|
||||
| 6 | 🟡 P1 | router.rs | risk | cost_tier/intelligence 路由已解耦,但枚举保留,无实际数据源接入 |
|
||||
| 7 | 🟡 P1 | retry.rs | risk | `MAX_COMPLETE_ATTEMPTS=3` 硬编码,不支持 per-provider 配置 |
|
||||
| 8 | 🟢 P2 | types.rs | smell | `ChatMessage` 18 个字段,构造时 `..` 语法极易遗漏新字段 |
|
||||
| 9 | 🟢 P2 | model.rs | smell | `ModelConfig` 11 个字段,`with_defaults` 默认值集中管理但调用方仍可改 |
|
||||
| 10 | 🟢 P2 | sse_parser.rs | smell | SSE 解析器自实现替代 eventsource-stream,但 BUF_MAX 1MB 无保护 |
|
||||
|
||||
---
|
||||
|
||||
## 🔴 P0 问题详述
|
||||
|
||||
### #1 openai_compat + anthropic_compat 大量重复
|
||||
|
||||
**问题**: 两个文件合计 113KB,逐行阅读发现大量重复代码:
|
||||
- `convert_request` 消息映射(OpenAI/Anthropic 格式互转)
|
||||
- 流式解析逻辑(chunk 事件 → StreamChunk)
|
||||
- 工具调用解析(tool_calls 提取)
|
||||
- 错误处理(HTTP 状态码 → 错误分类)
|
||||
- usage 累加
|
||||
|
||||
**具体重复区域**:
|
||||
- 工具调用解析: `parse_tool_calls` 在 `openai_helpers.rs` 而 `anthropic_helpers.rs` 有等效实现
|
||||
- 流式 chunk 解析: 两套 `parse_stream_line` / `parse_anthropic_event`
|
||||
- 请求构建: `build_request_body` 两套
|
||||
|
||||
**建议**: 抽共享 `provider_helpers.rs`,通用逻辑(工具解析/usage 合并/错误分类)放 df-ai-core(零 HTTP),HTTP 特有逻辑放 df-ai 共享模块。
|
||||
|
||||
### #2 coordinator.rs 65KB
|
||||
|
||||
**问题**: 单文件 65KB,是 DevFlow 单体最大文件。职责包括:
|
||||
- 多 agent 任务分发
|
||||
- 状态管理
|
||||
- 内存上下文
|
||||
- Scheduling
|
||||
|
||||
**建议**: 拆为 `coordinator/mod.rs` + `coordinator/tasks.rs` + `coordinator/scheduler.rs` + `coordinator/state.rs`。
|
||||
|
||||
### #3 context_helpers.rs 63KB
|
||||
|
||||
**问题**: 63KB 纯辅助函数,包括 `TokenEstimator` / `ContextConfig` / `MessageGroup` / `EvictionUnit` / `classify_group` / `PROTECT_COUNT` 等。
|
||||
|
||||
**建议**: 拆为 `context_helpers/token.rs` / `context_helpers/config.rs` / `context_helpers/classify.rs`。
|
||||
|
||||
---
|
||||
|
||||
## 🟡 P1 问题
|
||||
|
||||
### #6 router cost_tier/intelligence 悬空
|
||||
|
||||
**文件**: `router.rs`
|
||||
**风险**: 路由已解耦但枚举保留,无实际数据源接入。`cost_tier` 和 `intelligence` 字段在 `ModelConfig` 中存在但永远不参与路由判断。
|
||||
|
||||
**建议**: 添加注释说明恢复计划,或移除但保留 `ModelConfig` 字段供前端展示。
|
||||
|
||||
### #7 retry.rs 硬编码
|
||||
|
||||
**文件**: `retry.rs:26`
|
||||
**现状**: `MAX_COMPLETE_ATTEMPTS=3` 硬编码,不支持 `AiProviderRecord.config` 覆盖。
|
||||
|
||||
**建议**: 暴露 `with_max_attempts(n)` 或从 config 读取。
|
||||
|
||||
---
|
||||
|
||||
## 正面评价
|
||||
|
||||
1. **df-ai-core 分层正确**: trait+类型拆到轻量 crate,df-ideas 等不引入 HTTP 重依赖
|
||||
2. **retry.rs 设计优秀**: 指数退避 + jitter + 可重试/不可重试分类 + 预算上限,覆盖全面
|
||||
3. **sse_parser 容错**: 宽松 UTF-8 处理,多字节续接,BUF_MAX 防御
|
||||
4. **ChatMessage id 生成**: 单调递增 + 全局唯一,AtomicU64 双保险
|
||||
5. **tool_call_id_or_fallback**: 全局计数器防跨轮重复,实证修复
|
||||
6. **ModelConfig 向后兼容**: deserialize_model_configs 兼容老格式字符串数组
|
||||
7. **router 过滤链清晰**: enabled → 模态 → 能力 → 窗口 → weight,5 步清晰
|
||||
@@ -0,0 +1,90 @@
|
||||
# df-storage + df-ideas + df-mcp 代码走查报告
|
||||
|
||||
> 走查日期: 2026-08-02
|
||||
> 范围: crates/df-storage/ (7 files, ~142KB) + crates/df-ideas/ (7 files, ~63KB) + crates/df-mcp/ (3 files, ~52KB)
|
||||
|
||||
---
|
||||
|
||||
## 一、df-storage 存储层
|
||||
|
||||
### 文件规模
|
||||
|
||||
| 文件 | 行数 | 类型 |
|
||||
|---|---|---|
|
||||
| migrations.rs | 89,663 | 迁移脚本(37 个版本) |
|
||||
| models.rs | 24,880 | 15 个数据模型 |
|
||||
| secret.rs | 16,523 | 密钥管理(keyring) |
|
||||
| crud/mod.rs | 14,919 | Repo 宏 + 公共工具 |
|
||||
| crud/task_repo.rs | 42,011 | 任务 Repo |
|
||||
| crud/idea_repo.rs | 65,123 | 灵感 Repo |
|
||||
| crud/conversation_repo.rs | 23,614 | 对话 Repo |
|
||||
| crud/message_repo.rs | 26,633 | 消息 Repo |
|
||||
| crud/project_repo.rs | 20,753 | 项目 Repo |
|
||||
| crud/settings.rs | 11,778 | 列白名单 |
|
||||
|
||||
### 问题汇总
|
||||
|
||||
| # | 等级 | 文件 | 类型 | 简述 |
|
||||
|---|---|---|---|---|
|
||||
| 1 | 🟡 P1 | migrations.rs | smell | 89KB 单文件,37 个迁移函数全在一个文件,V1 建表 SQL 也嵌在里面 |
|
||||
| 2 | 🟡 P1 | secret.rs | risk | keyring 在 Linux 无 GUI 会话时静默失败,`set_provider_secret` 返回 Err 但上层不处理 |
|
||||
| 3 | 🟡 P1 | db.rs | risk | 单连接 `Mutex<Connection>`,GUI + MCP server 并发读写时锁竞争 |
|
||||
| 4 | 🟡 P1 | crud/mod.rs | risk | `impl_repo!` 宏生成的 `update_field` 不校验 entity_type(已知缺陷 B-260801-01) |
|
||||
| 5 | 🟡 P1 | crud/idea_repo.rs | smell | 65KB 单文件,灵感 Repo 含知识库/向量工具,职责过宽 |
|
||||
| 6 | 🟡 P1 | crud/task_repo.rs | smell | 42KB 单文件,含 `advance_status_atomic` 状态机收口 |
|
||||
| 7 | 🟢 P2 | secret.rs | smell | 迁移失败计数 sidecar 文件用 `.devflow-keyring-failcount`,路径依赖 cwd |
|
||||
| 8 | 🟢 P2 | models.rs | smell | `AiProviderRecord` 的 `Debug` 手动脱敏,新增字段易漏 |
|
||||
| 9 | 🟢 P2 | migrations.rs | smell | 37 个迁移版本,V1 建表 SQL 内联,V21 消息拆表迁移函数长 |
|
||||
|
||||
### 正面评价
|
||||
|
||||
1. **胡盾宏 impl_repo!**: 消除 14 个 Repo 的重复样板,from_row/insert/update 三体分离
|
||||
2. **迁移幂等**: column_exists 探测,新库/老库/坏数据均不崩
|
||||
3. **WAL 模式**: `PRAGMA journal_mode=WAL` 已启用,GUI + MCP 并发安全
|
||||
4. **密钥管理**: keyring 迁移 + 失败计数阈值 + 显示告警,设计完整
|
||||
5. **ensure_resolved_key**: 归一化(trim/剥引号)防粘贴脏 key
|
||||
6. **列白名单**: `allowed_columns_for` 每表独立白名单,防 SQL 注入
|
||||
7. **基线测试**: `all_known_tables_have_column_whitelist` 防新增表漏白名单
|
||||
|
||||
---
|
||||
|
||||
## 二、df-ideas 灵感评估
|
||||
|
||||
### 问题汇总
|
||||
|
||||
| # | 等级 | 文件 | 类型 | 简述 |
|
||||
|---|---|---|---|---|
|
||||
| 1 | 🟡 P1 | adversarial.rs | smell | 296KB 单文件,引擎 + 测试混在一起,测试应拆到独立文件 |
|
||||
| 2 | 🟡 P1 | adversarial_helpers.rs | risk | 拒绝语义化关键字 `"no"` 过宽,`"no problem"` 等文本可能误判 |
|
||||
| 3 | 🟢 P2 | scoring.rs | smell | 关键词匹配 `count_any` 否定前缀处理复杂,但只处理单字+两字否定 |
|
||||
| 4 | 🟢 P2 | scoring_keywords.rs | smell | 关键词硬编码,最佳实践应为 JSON 配置 |
|
||||
| 5 | 🟢 P2 | adversarial.rs | risk | `evaluate_with_llm` 返回一致性未校验,ARC-260618-01-e 待决策 |
|
||||
|
||||
### 正面评价
|
||||
|
||||
1. **对抗评估架构**: 启发式/LLM 双轨 + 自动降级,`evaluated_by` 三态标记前端可展示
|
||||
2. **LLM prompt 设计**: 三角色辩论 + 严格 JSON schema + 截断保护
|
||||
3. **parse_llm_eval 容错**: 剥离 ```json 围栏 + 正则兜底 + 枚举映射 + 数值 clamp
|
||||
4. **评分引擎**: 否定前缀处理(不复用反向不计入复用正向分),设计精细
|
||||
5. **测试覆盖**: adversarial 7 个启发式 + 1 个 LLM mock 测试,scoring 10 个测试
|
||||
|
||||
---
|
||||
|
||||
## 三、df-mcp MCP Server
|
||||
|
||||
### 问题汇总
|
||||
|
||||
| # | 等级 | 文件 | 类型 | 简述 |
|
||||
|---|---|---|---|---|
|
||||
| 1 | 🟡 P1 | tools.rs | smell | 31KB 单文件,19 个 handler + 工具定义全在一起 |
|
||||
| 2 | 🟡 P1 | tools.rs | risk | `Box::leak` 静态化工具定义,但 `all_tools()` 每次调用重新构建 Vec |
|
||||
| 3 | 🟢 P2 | server.rs | smell | dispatch 中 `high_risk` 兜底拒绝与 `visible` 过滤双重检查,但 `visible` 已过滤 High |
|
||||
| 4 | 🟢 P2 | protocol.rs | smell | `McpMethod::from_request` 中 `tools/call` 的 arguments 取 `req.params.get("arguments")`,可能为 null |
|
||||
|
||||
### 正面评价
|
||||
|
||||
1. **安全设计**: High 风险工具默认拒绝,read-only 模式仅 Low,双保险
|
||||
2. **协议实现**: 完整 JSON-RPC 2.0 + MCP 2025-06-18 协议
|
||||
3. **测试覆盖**: initialize/list/call/High拒绝/read-only/create-then-list 全路径覆盖
|
||||
4. **handler 函数指针**: 避免闭包捕获生命周期问题
|
||||
5. **medium_audit 审计日志**: Medium 风险工具调用有 tracing::warn 审计
|
||||
@@ -0,0 +1,105 @@
|
||||
# df-relay + df-tunnel + df-project + df-types + df-execute 代码走查报告
|
||||
|
||||
> 走查日期: 2026-08-02
|
||||
> 范围: df-relay(5 文件, 30KB) + df-tunnel(3 文件, 32KB) + df-project(2 文件, 21KB) + df-types(3 文件, 42KB) + df-execute(2 文件, 34KB)
|
||||
|
||||
---
|
||||
|
||||
## 一、df-relay 云中继
|
||||
|
||||
### 问题汇总
|
||||
|
||||
| # | 等级 | 文件 | 类型 | 简述 |
|
||||
|---|---|---|---|---|
|
||||
| 1 | 🟡 P1 | relay.rs | risk | token 鉴权用 `env DF_RELAY_TOKEN` 全局常量,生产级应有独立 token 每 device |
|
||||
| 2 | 🟡 P1 | relay.rs | risk | 注册表 `tokio::sync::Mutex` 锁粒度粗,高并发连接时瓶颈 |
|
||||
| 3 | 🟢 P2 | conn.rs | smell | `ConnRegistry::route` 中 `BroadcastMessage` 字段 `kind`/`from`/`handle.kind` 三因子匹配,可读性差 |
|
||||
| 4 | 🟢 P2 | broadcast.rs | smell | `ControlMessage` 定义了但 `handle_inbound_text` 中只处理 `ping`,其余控制消息未实现 |
|
||||
|
||||
### 正面评价
|
||||
|
||||
1. **架构清晰**: Event/Command/Control 三方向路由,语义明确
|
||||
2. **Hello 握手**: 双因子校验(kind + token),超时 10s,error 帧回显
|
||||
3. **心跳处理**: 小程序 ping → relay pong 本地响应,不经过 device
|
||||
4. **BroadcastMessage 全字段**: device_id/kind/source/from/payload/ts,路由信息完整
|
||||
|
||||
---
|
||||
|
||||
## 二、df-tunnel 隧道客户端
|
||||
|
||||
### 问题汇总
|
||||
|
||||
| # | 等级 | 文件 | 类型 | 简述 |
|
||||
|---|---|---|---|---|
|
||||
| 1 | 🟡 P1 | tunnel.rs | risk | 重连退避逻辑写了 `backoff_delay` 函数但未实现自动后台重连,需手动 connect |
|
||||
| 2 | 🟡 P1 | tunnel.rs | risk | `cleanup_conn` 中 `select!` 500ms 超时后 abort task,可能丢最后一帧 |
|
||||
| 3 | 🟢 P2 | tunnel.rs | smell | `WsTunnelClient` 持 3 个 `Mutex<Option<String>>`(server_url/device_id/token),可合并为单 struct |
|
||||
| 4 | 🟢 P2 | tunnel.rs | smell | `connect` 方法 130 行,逻辑过重,可拆为 `do_connect` + `handshake` + `start_loop` |
|
||||
|
||||
### 正面评价
|
||||
|
||||
1. **协议对齐**: 与 df-relay 的 Hello 握手协议一致
|
||||
2. **connect_timeout**: 15s 超时防 TCP SYN 无响应时永久挂
|
||||
3. **HANDSHAKE_PROBE**: 3s 窗口探测 relay 是否拒绝,防静默失败
|
||||
4. **心跳间隔**: 25s 应用层 Ping,防 NAT 连接表超时回收
|
||||
5. **CommandHandler**: `BoxFuture` 回调,不阻塞收发循环
|
||||
6. **send_raw_event**: AiChatEvent 全 19 变体透传,不依赖强类型
|
||||
|
||||
---
|
||||
|
||||
## 三、df-project 项目管理
|
||||
|
||||
### 问题汇总
|
||||
|
||||
| # | 等级 | 文件 | 类型 | 简述 |
|
||||
|---|---|---|---|---|
|
||||
| 1 | 🟢 P2 | manager.rs | smell | `ProjectManager::create` 纯领域层工厂,但 `Project` 实体与 `ProjectRecord` 模型不同源 |
|
||||
| 2 | 🟢 P2 | scan_helpers.rs | smell | 图片收集 `is_badge_image` 依赖域名+关键词列表,`is_pure_badge_line` 行级扫描逻辑复杂 |
|
||||
|
||||
### 正面评价
|
||||
|
||||
1. **状态机完整**: `can_transition` 矩阵清晰,`transition` 返回 `TerminalState`/`IllegalTransition` 区分
|
||||
2. **scan_helpers 纯函数**: 无 IO 依赖,`strip_readme_noise` 处理 frontmatter/HTML注释/TOC/徽章
|
||||
3. **否定前缀处理**: 单字(不/无/非/未/没/勿)+两字(没有/并非/毫无等)否定前缀,设计精细
|
||||
4. **测试覆盖**: manager.rs 7 个测试,scan_helpers.rs 10 个测试
|
||||
|
||||
---
|
||||
|
||||
## 四、df-types 类型定义
|
||||
|
||||
### 问题汇总
|
||||
|
||||
| # | 等级 | 文件 | 类型 | 简述 |
|
||||
|---|---|---|---|---|
|
||||
| 1 | 🟢 P2 | augmentation.rs | smell | 21KB 单文件,MentionRef/Augmentation/ResolveError 三个模块混在一起 |
|
||||
| 2 | 🟢 P2 | types.rs | smell | `ExecutionId`/`ToolCallType` newtype 大量 `From`/`PartialEq` 样板,可取 derive_more |
|
||||
|
||||
### 正面评价
|
||||
|
||||
1. **SanitizedPath newtype**: 脱敏路径强制类型化,防裸 String 误用
|
||||
2. **MentionRef/Augmentation 双结构**: resolve 前/后分离,职责清晰
|
||||
3. **serde tag=kind**: 四种变体统一 json 结构,前端可共用 chip 渲染
|
||||
4. **TaskStatus 双源一致性**: `as_str()` const fn + `valid_values()` 测试锁定
|
||||
5. **WorkflowEvent 兼容**: `#[serde(default)]` 向后兼容老事件
|
||||
|
||||
---
|
||||
|
||||
## 五、df-execute 命令执行
|
||||
|
||||
### 问题汇总
|
||||
|
||||
| # | 等级 | 文件 | 类型 | 简述 |
|
||||
|---|---|---|---|---|
|
||||
| 1 | 🟡 P1 | shell.rs | risk | `build_command` 中 `ShellType::default()` 依赖 `PWSH_CACHE` 异步填充,首次 `execute` 可能读到未初始化 |
|
||||
| 2 | 🟡 P1 | env_snapshot.rs | risk | `probe_version` 内 `std::process::Command::output()` 无 timeout,Windows Store alias 卡死(已修复 5s timeout) |
|
||||
| 3 | 🟢 P2 | shell.rs | smell | `execute_streaming` 的 `on_output` 回调在 `select!` 中调用,`FnMut` 不可重入 |
|
||||
|
||||
### 正面评价
|
||||
|
||||
1. **PWSH_CACHE 单源**: 异步 probe + 同步读取,死缓存已修复
|
||||
2. **execute_streaming**: mpsc 通道解耦 + 逐行回调 + read_to_end 兜底
|
||||
3. **kill_on_drop**: 超时后子进程不残留
|
||||
4. **CREATE_NO_WINDOW**: Windows 后台静默执行不弹黑窗
|
||||
5. **env_snapshot 超时兜底**: 5s timeout + spawn_blocking 防永久卡
|
||||
6. **extract_version_token**: 鲁棒版本号提取,"2.41.0.windows.1" → "2.41.0"
|
||||
7. **测试覆盖**: shell.rs 探测缓存测试,env_snapshot 7 个测试
|
||||
+7
-1
@@ -80,9 +80,15 @@ docs/
|
||||
│ ├── DEVFLOW-3.Store对接实施-2026-06-12.md
|
||||
│ └── DEVFLOW-4.端到端验证-2026-06-12.md
|
||||
├── 05-代码审查/
|
||||
│ ├── 00-全库代码走查汇总-2026-08-02.md # 全库走查汇总(12 crate, 78 问题, 11 P0 / 30 P1 / 37 P2)
|
||||
│ ├── 01-df-nodes-走查-2026-08-02.md # 17 节点走查(20 问题)
|
||||
│ ├── 02-df-workflow-走查-2026-08-02.md # 工作流引擎走查(9 问题)
|
||||
│ ├── 03-df-ai-走查-2026-08-02.md # AI 核心走查(13 问题)
|
||||
│ ├── 04-df-storage-ideas-mcp-走查-2026-08-02.md # 存储/灵感/MCP 走查(17 问题)
|
||||
│ ├── 05-df-relay-tunnel-project-types-execute-走查-2026-08-02.md # 中继/隧道/项目管理/类型/执行走查(19 问题)
|
||||
│ ├── 全栈代码审查报告-2026-06-14.md # Rust+Tauri+Vue 全栈审查(5 代理并行)
|
||||
│ ├── 架构与缺陷复核报告-2026-06-14.md # 复核已修项 + 回归审计 + 架构层补充(4 路并行)
|
||||
│ ├── 近期改动代码审查-2026-06-15.md # 工作区 FR-S1/S7/S8 + 近 5 提交(3 路并行)
|
||||
│ ├── 近期改动代码审查-2026-06-15.md # 工作区 FR-S1/S7/S8
|
||||
│ ├── 架构审查-2026-06-15.md # 纯架构层(边界/依赖/抽象/扩展性),8 crate + 前端(2 路并行)
|
||||
│ ├── 自研块级memo流式渲染审查-2026-06-15.md # ARC-260615-08 实施走查(splitBlocks/parseBlock/rAF)
|
||||
│ ├── 工作区多角度走查-2026-06-15.md # 工作区22文件547行4路并行(selectType/队列收尾/骨架屏/i18n/DRY)
|
||||
|
||||
Reference in New Issue
Block a user