新增: 批次工作落地(推进链/评估闭环/事件总线/并发/加固) + 技术债清理 + 文档整理

后端:
- 工作流推进链(D-03):advance_task/状态机/闸门走 df-nodes Node trait,conditions 条件引擎扩展
- 想法评估闭环:启发式评分+对抗评估,df-ideas/scoring + df-storage/idea_eval_repo + idea 前端打通
- 全局事件数据总线:df-ai/context+context_helpers+augmentation 跨模块解耦
- AI planner/plan_hint/intent:aichat B 路线并行多轮基础
- patch_file 加固(TD-03/04):读改写整体锁防 lost update,expected_hash 合约闭环
- 压缩超时兜底(F-15 卡死根治)
- F-09 多会话并发:LlmConcurrency per-conv + streamingGuard 前端守护 + verify 脚本
- 知识注入 DRY/skills/audit 扩展

清理:
- aichat 技术债(误报 allow/死导入/过时注释 30 项)
- URGENT.md 删除(11 项加急全解决/迁 todo)
- 文档整理(todo/待决策/待审查/ARCHITECTURE/INDEX + 总线/技术债审查新文档)
This commit is contained in:
2026-06-21 20:51:26 +08:00
parent 330bb7f505
commit bd6a41fe6e
111 changed files with 11932 additions and 1034 deletions

View File

@@ -7,7 +7,7 @@ use std::collections::HashSet;
use crate::state::AppState;
use super::super::PendingApproval;
use super::super::{ApprovalKind, PendingApproval};
use super::risk_from_str;
/// 启动恢复:从审计表重建 pending_approvals(重启前未审批的工具调用,内存态已丢)
@@ -64,19 +64,26 @@ pub async fn restore_pending_approvals(state: &AppState) {
arguments: args,
conversation_id: rec.conversation_id,
recovered: true,
// 阶段3a 单真相源合并:恢复的审批一律 kind=Risk(diff=None,与原顶层 diff 字段同语义)。
//
// **path 审批不恢复的决策(语义保留)**:路径授权挂起是会话级状态,重启后 session
// 重建,无法恢复挂起语义;且 path 的"always"决策已写入持久白名单(Settings KV),
// 重启后白名单仍生效(文件工具路径预校验会直接 Authorized,不再挂起)。故 path 审批
// 无需恢复 —— 恢复 risk 即可覆盖所有需人工决策的积压。
//
// AE-2025-03: 重启恢复的审批不重读旧文件——审批可能跨重启,
// 期间文件可能已被外部改动,重读生成 diff 反映的不是当初决策时的状态,
// 且恢复路径在 session.lock 内做 async IO 复杂度高,预览价值低。
// 前端见 diff=None 时回退显新 content。
diff: None,
// F-260619-03 Phase B: 重启恢复的审批一律视为普通 RiskLevel 审批(非路径授权挂起)。
// 路径授权挂起是会话级状态,重启后 session 重建,无法恢复挂起语义
path_auth: None,
kind: ApprovalKind::Risk { diff: None },
// 阶段4:重启恢复的审批 retry_count=0(恢复语义即"待用户首次决策",非重试)。
// 即便审计表已有 pending 记录,恢复后用户审批执行属首次正常执行,不断路
retry_count: 0,
},
);
}
tracing::info!(
"启动恢复: {} 条 pending 工具审批重建到内存, 分布 {} 个 conv 的 per_conv",
"启动恢复: {} 条 pending 工具审批重建到内存(pending_approvals), 分布 {} 个 conv 的 per_conv",
session.pending_approvals.len(),
convs_restored.len()
);
@@ -84,7 +91,7 @@ pub async fn restore_pending_approvals(state: &AppState) {
#[cfg(test)]
mod tests_f09_batch8_restore {
use super::super::PendingApproval;
use super::super::{ApprovalKind, PendingApproval};
use super::*;
use crate::commands::ai::AiSession;
@@ -114,7 +121,7 @@ mod tests_f09_batch8_restore {
let _ = session.conv(cid); // 惰性建
}
}
// pending 入单层 HashMap(不进 per_conv,设计 §2.1.2)
// 阶段3a 单真相源合并:恢复的 pending 全部进 pending_approvals,kind=Risk
session.pending_approvals.insert(
tool_call_id.clone(),
PendingApproval {
@@ -123,8 +130,9 @@ mod tests_f09_batch8_restore {
arguments: serde_json::Value::Null,
conversation_id: conversation_id.clone(),
recovered: true,
diff: None,
path_auth: None,
kind: ApprovalKind::Risk { diff: None },
// 阶段4:恢复的审批 retry_count=0(首次用户决策,非重试)。
retry_count: 0,
},
);
}
@@ -138,8 +146,17 @@ mod tests_f09_batch8_restore {
"未恢复的 conv 不应被惰性建"
);
// 不变量 2:pending_approvals 单层 HashMap 4 条(含无主),conversation_id 保留(业务语义)。
assert_eq!(session.pending_approvals.len(), 4, "全部 pending 入单层 HashMap");
// 不变量 2:pending_approvals HashMap 4 条(含无主),conversation_id 保留(业务语义)。
// 阶段3a:全部进单表 pending_approvals(原 risk_pending 合一,path 审批不恢复)。
assert_eq!(session.pending_approvals.len(), 4, "全部 pending 入 pending_approvals");
// 构造期恒等式:上方 pending_rows 构造的 4 条 PendingApproval 全部 kind=Risk(本测试构造
// 时未插入任何 Path(_)),故 filter Path(_) 计数必为 0。这是构造恒等式而非外部不变量——
// 对齐真实 restore_pending_approvals 的构造(实现 L78 一律 kind=Risk,无 Path 分支)。
// 语义:首次 restore 无历史(Path 审批是会话级状态不恢复,恢复侧构造时本就不产出 Path)。
let path_restored = session.pending_approvals.values()
.filter(|a| matches!(a.kind, ApprovalKind::Path(_)))
.count();
assert_eq!(path_restored, 0, "构造期恒等式:恢复侧构造全部 kind=Risk,无 Path(首次 restore 无历史)");
let conv_a_pending: Vec<_> = session
.pending_approvals
.values()
@@ -157,7 +174,7 @@ mod tests_f09_batch8_restore {
.values()
.filter(|a| a.conversation_id.is_none())
.collect();
assert_eq!(ownerless.len(), 1, "无主审批 1 条仍入单层表(R-9)");
assert_eq!(ownerless.len(), 1, "无主审批 1 条仍入 pending_approvals(R-9)");
// 不变量 3:同 conv 多条 pending 复用同一 PerConvState(conv() 幂等,不重复建)。
let conv_a_ptr = session.conv("conv-a") as *const _;