From b994cf2c541ee3539c8d23d20c08b3d131d9e5bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BB=9D=E5=B0=98?= <237809796@qq.com> Date: Sun, 4 Oct 2026 16:06:08 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=87=E6=A1=A3:=20=E8=AE=BE=E8=AE=A1?= =?UTF-8?q?=E5=AE=9A=E7=A8=BF=E4=B8=8E=E8=AF=84=E4=BC=B0=E7=BA=AA=E5=BE=8B?= =?UTF-8?q?=E7=99=BB=E8=AE=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 无人值守长任务设计定稿,含效率与可观测补遗 - u-relay wire 协议规格与五项评估结论 - 新能力引入评估纪律五项清单 - todo 销账与狗粮短板分析登记 --- ...context-helpers拆分备勘-设计-2026-10-04.md | 61 ++++ ...devflow集成u-claw-可行性研究-2026-09-28.md | 2 +- .../namespace淘汰治理-设计-2026-10-04.md | 91 +++++ .../u-relay-wire-protocol-2026-10-04.md | 254 ++++++++++++++ .../专项设计/uclaw两侧勘察补全-2026-10-04.md | 75 +++++ .../子代理完成卡已消化降级-设计-2026-10-04.md | 97 ++++++ .../无人值守长任务-设计-2026-10-04.md | 318 ++++++++++++++++++ .../跨会话召回最小闭环-设计-2026-10-04.md | 90 +++++ .../02-架构设计/滚动规范/拍板集-2026-10-04.md | 99 ++++++ docs/todo.md | 147 ++++++-- 10 files changed, 1214 insertions(+), 20 deletions(-) create mode 100644 docs/02-架构设计/专项设计/context-helpers拆分备勘-设计-2026-10-04.md create mode 100644 docs/02-架构设计/专项设计/namespace淘汰治理-设计-2026-10-04.md create mode 100644 docs/02-架构设计/专项设计/u-relay-wire-protocol-2026-10-04.md create mode 100644 docs/02-架构设计/专项设计/uclaw两侧勘察补全-2026-10-04.md create mode 100644 docs/02-架构设计/专项设计/子代理完成卡已消化降级-设计-2026-10-04.md create mode 100644 docs/02-架构设计/专项设计/无人值守长任务-设计-2026-10-04.md create mode 100644 docs/02-架构设计/专项设计/跨会话召回最小闭环-设计-2026-10-04.md create mode 100644 docs/02-架构设计/滚动规范/拍板集-2026-10-04.md diff --git a/docs/02-架构设计/专项设计/context-helpers拆分备勘-设计-2026-10-04.md b/docs/02-架构设计/专项设计/context-helpers拆分备勘-设计-2026-10-04.md new file mode 100644 index 0000000..b502c9b --- /dev/null +++ b/docs/02-架构设计/专项设计/context-helpers拆分备勘-设计-2026-10-04.md @@ -0,0 +1,61 @@ +# context_helpers.rs 拆分备勘(REFACTOR-260619-09 修订)· 设计(2026-10-04) + +> 来源:todo.md「REFACTOR-260619-09 [P2 暂缓] — context.rs(1332)等 F-15 压缩链路稳定再拆」。 +> **勘误(2026-10-04 现场核实)**:原条目指向的 `crates/df-ai/src/context.rs`(1332 行)**已不存在**——context 已拆为目录模块 `context/{mod.rs(38.5KB), sanitize.rs(64.5KB), manager_tests.rs(51.8KB)}`。**原 REFACTOR-260619-09 事实完成,建议 todo 销账**。 +> 但拆分域出现**新超标 God 文件**:`crates/df-ai/src/context_helpers.rs` = **1733 行**(80KB,无测试分离),TokenEstimator/ContextConfig/工具结果压缩/分组/淘汰/公共工具混居。本设计以它为对象。 +> 同域现状参考:df-ai/src/ 下平级大文件尚有 coordinator.rs(68.7KB)、intent.rs(66.8KB)、anthropic_compat.rs(69.9KB)、openai_compat.rs(65.4KB)——均超 60KB,属后续拆分候选池,本期不扩scope。 + +## 1. 拆分对象画像 + +`context_helpers.rs` 1733 行,混合至少六类职责(已知锚点): +- **Token 估算**:TokenEstimator 相关(行段待精确,拆时以 read_symbol 逐个锚定); +- **上下文配置**:ContextConfig 及常量; +- **工具结果压缩**:`:410 TOOL_RESULT_SUMMARIZE_BYTES=2048`、`:425 TOOL_RESULT_JSON_STR_FIELD_MAX=512`、`should_summarize_tool_result(:440)`、extract_key_info 系列(head/tail/array/char/json-str 五种截断); +- **namespace 引用转发**:`:646-647 NAMESPACE_REF_PREFIX`(仅常量 re-export,薄); +- **淘汰/分组逻辑**(eviction/grouping,与 context/mod.rs 的 ContextManager 呼应); +- **杂项公共工具**(is_han `:396` 等纯函数)。 + +**前置动作(拆分前 0.5 天)**:用 read_symbol 对 1733 行做一次全骨架清点,产出「函数→职责块→行段」映射表落 `docs/05-代码审查/context_helpers骨架-2026-10-XX.md`——本设计给出块划分与迁移策略,具体行号以骨架表为准。 + +## 2. 目标模块划分(建议) + +拆为 `context_helpers/` 目录(与 context/ 同款目录化先例,lib.rs 加 `pub mod` 不动外部路径——`df_ai::context_helpers::X` 引用形态不变): + +| 子模块 | 职责 | 预计行数 | 风险 | +|---|---|---|---| +| `token.rs` | TokenEstimator + 估算纯函数 | ~250 | 低(纯函数,单测易迁) | +| `config.rs` | ContextConfig + 阈值常量(含 TOOL_RESULT_* 六常量) | ~150 | 低 | +| `tool_compress.rs` | should_summarize_tool_result + extract_key_info 系列 | ~350 | **中(压缩热点,殿后)** | +| `eviction.rs` | 淘汰/分组 + namespace 常量转发 | ~400 | **中高(压缩链路高频改动区,殿后)** | +| `misc.rs` | is_han 等纯工具(或就近下沉使用方) | ~100 | 低 | +| `mod.rs` | re-export 保路径 + 少量真公共胶水 | ~50 | — | + +**测试**:本文件测试与生产代码混居(无 #[cfg(test)] 分离迹象,拆时确认)——随成员走,`token.rs`/`tool_compress.rs` 各带自己的测试模块;若测试体量大,仿照 context/manager_tests.rs 惯例平级 `helpers_tests.rs`。 + +## 3. 迁移顺序(四批,压缩热点殿后) + +``` +批1 低风险: config.rs + misc.rs → cargo test -p df-ai 全绿 +批2 低风险: token.rs (+其单测) → 同上 +批3 热点: tool_compress.rs → 同上 + 手测长会话压缩路径 +批4 热点: eviction.rs + mod.rs 收口 → 同上 + 手测 eviction 滚动摘要 +``` + +每批验收门:`cargo test -p df-ai`(基线 560+)+ `cargo check --workspace`;批3/4 加:起应用开长会话触发压缩与淘汰各一次,行为无回归。**每批独立提交**,冲突时可安全停在任意批。 + +## 4. re-export 兼容策略 + +`context_helpers/mod.rs` 对全部原 pub 项 `pub use` 转发——仓内 grep 显示引用方走 `df_ai::context_helpers::*` 与 `crate::context_helpers::*` 两种路径,目录化后**零调用方改动**。仅 `use df_ai::context_helpers` 整体 use(若有)需 mod.rs 全量 re-export 兜住。 + +## 5. 与原条目的关系 + +- todo 销账动作:REFACTOR-260619-09 原 context.rs 拆分 ✅ 完成;**新登记**本设计为 REFACTOR-261004-01(context_helpers.rs 1733 行拆分),优先级维持 P2 暂缓——**触发条件**:上下文管理批(无人值守 P0/P1)合入且稳定 ≥1 周后启动批1/2(低风险先行),批3/4 继续等压缩链路静默期; +- context_helpers.rs 若在触发前因功能开发继续膨胀 >2000 行,优先把「工具结果压缩」块先行拆出(批3 提前),不整文件硬拆。 + +## 6. 工作量估算 + +骨架清点 0.5 天 + 批1/2 各 0.5 天 + 批3/4 各 1 天 ≈ 3.5 天(可拆散穿插,非连续占用)。 + +## 7. 拍板点(1 项) + +- 触发时机:上下文管理批稳定后自动启动 vs 等用户指令?建议**等用户指令**(与 REFACTOR 暂缓惯例一致,本设计备勘即可)。 diff --git a/docs/02-架构设计/专项设计/devflow集成u-claw-可行性研究-2026-09-28.md b/docs/02-架构设计/专项设计/devflow集成u-claw-可行性研究-2026-09-28.md index 20a4b15..780dd35 100644 --- a/docs/02-架构设计/专项设计/devflow集成u-claw-可行性研究-2026-09-28.md +++ b/docs/02-架构设计/专项设计/devflow集成u-claw-可行性研究-2026-09-28.md @@ -1,6 +1,6 @@ # devflow → u-relay → u-claw 集成可行性研究 -> 2026-09-28 · 状态:可行性已定,待 devflow/u-claw 两侧细勘察补全 +> 2026-09-28 · 状态:可行性已定 ~~待 devflow/u-claw 两侧细勘察补全~~ ✅勘察已补全(2026-10-04,见 [uclaw两侧勘察补全-2026-10-04.md](./uclaw两侧勘察补全-2026-10-04.md)——多轮锚定定案+**协议漂移修正:现行 /ws/commander 角色,实施勿按本文档端点**) > 需求原话:「考虑 devflow -> u-relay -> u-claw, 让 devflow 集成 u-claw 能力」 ## 一、定性结论 diff --git a/docs/02-架构设计/专项设计/namespace淘汰治理-设计-2026-10-04.md b/docs/02-架构设计/专项设计/namespace淘汰治理-设计-2026-10-04.md new file mode 100644 index 0000000..1468ec9 --- /dev/null +++ b/docs/02-架构设计/专项设计/namespace淘汰治理-设计-2026-10-04.md @@ -0,0 +1,91 @@ +# Namespace 淘汰互踩治理 · 设计(2026-10-04) + +> ✅ 拍板通过(2026-10-04,2/2 按建议:C1 pin 50% 上限/C2 本期仅报告 pin;见 [拍板集](../滚动规范/拍板集-2026-10-04.md)) + +> 来源:todo.md 子代理深查「P2 namespace 10MB 全局 LRU 淘汰:报告蒸发为『重新调用』死路+多代理共池互踩[需设计]」。 +> 勘察结论(2026-10-04 现场核实,以 `crates/df-ai/src/namespace_store.rs` 全文为准): +> - `NamespaceStore` = 纯内存 `HashMap` + 手动 LRU(`evict_if_needed`),默认 10MB(`:85 default()`),单条超容量拒绝入库(`:108`,返回不可解析引用→展开点落 `EVICTED_PLACEHOLDER`)。 +> - 阈值:`NAMESPACE_BYTE_THRESHOLD=2048` / `NAMESPACE_LINE_THRESHOLD=50`,`ALWAYS_LARGE_TOOLS=[read_file, list_directory, grep, diff_files]`。 +> - **无淘汰回调/通知**:淘汰静默发生,父 LLM 只在下次展开引用时经 `EVICTED_PLACEHOLDER`(`:17`)得知「已淘汰,如需请重新调用」。 +> - 展开点:`agentic/context_lifecycle.rs:145-155`(压缩路径)、`agentic/mod.rs:1632`(主循环),均 `is_namespace_ref` 检查。 +> - 作用域:store 实例按会话生命周期持有(`ContextManager` 或 agentic loop 内),**子代理 loop 复用同一全局/会话 store**——互踩根源。 + +## 1. 失败模式拆解 + +| 模式 | 现状 | 后果 | +|---|---|---| +| F1 报告蒸发死路 | 子代理 A 报告进 namespace → 池满淘汰 → 父 LLM 展开得 EVICTED_PLACEHOLDER → 指引「重新调用对应工具」 | 「重新调用」= 重跑子代理(spawn 新一轮),成本爆炸且非确定性 | +| F2 多代理互踩 | 同会话并发/串行多子代理共用一个 10MB 池,A 的大结果把 B 的挤掉 | 无归属概念,淘汰不看 owner | +| F3 跨会话残留 | 引用路径含 args_hash 不含会话维度,会话切换后引用可能指向别会话条目(或已蒸发) | 语义错乱(EVICTED_PLACEHOLDER 兜底但误导) | + +## 2. 设计目标 + +1. **报告类内容不可淘汰**(pin 机制):子代理报告、用户显式产出的长文标记 pin,LRU 跳过; +2. **淘汰可感知**:淘汰发生时记录「淘汰清单」,下次展开引用时给出**结构化**提示(含原工具名+参数摘要+淘汰时间),而非裸 EVICTED_PLACEHOLDER; +3. **隔离互踩**:store 增 owner 维度(conv_id 或子代理 id),淘汰优先跨 owner 不回收他域(软隔离,不引入硬配额复杂度); +4. **零 schema 变更**:全部内存态增强,不动 DB。 + +非目标:不做磁盘 spill(超容量落盘另线);不改阈值(2048B/50 行实测合理);不动 ALWAYS_LARGE_TOOLS 名单。 + +## 3. 方案 + +### 3.1 NamespaceEntry 扩展 + +``` +pub struct NamespaceEntry { + key, tool_name, content, created_at, access_count, // 现有 ++ pinned: bool, // pin 标记,LRU 跳过 ++ owner: Option, // 归属 conv_id/agent_id,软隔离 ++ evict_hint: Option, // 预生成的淘汰提示(工具名+参数前 80 字),淘汰时留档 +} +``` + +### 3.2 pin API + +``` +impl NamespaceStore { ++ pub fn store_pinned(&mut self, tool_name, content, owner) -> String // 子代理报告/关键产出走此 ++ pub fn pin(&mut self, key) // 事后 pin ++ pub fn unpin(&mut self, key) +} +``` + +调用点:`sub_agent.rs` 统一出口(:495 emit AiAgentFinished 处)把报告 `store_pinned`;`run_command`/`generate_image` 等大产出可选 pin(后续)。 + +### 3.3 淘汰清单(EvictionLog) + +store 内加 `VecDeque`(容量上限 50 条): + +``` +struct EvictionRecord { key, tool_name, hint(前80字), evicted_at, owner } +``` + +`evict_if_needed` 淘汰时 push。展开点 `read_only()=None` 时: +1. 查 EvictionLog 命中 → 返回富提示:`[结果已淘汰] 原为 read_file(src/main.rs 前 80 字…) 于 3 分钟前因容量淘汰。可重新调用 read_file 取回。` +2. 未命中(跨会话残留/未知)→ 现 EVICTED_PLACEHOLDER 不变。 + +### 3.4 owner 软隔离 + +`evict_if_needed` 淘汰顺序改为:**先淘无 owner 且未 pin 的最旧 → 再淘他 owner(非当前活跃 conv)未 pin → 最后当前 owner 未 pin**。pin 永不淘(除非 pin 总量超 50% 容量,此时最旧 pin 降级可淘——防 pin 滥用撑死池)。 + +### 3.5 store 传递 owner + +`store(tool_name, content)` → `store(tool_name, content, owner: Option<&str>)`。调用方在 agentic loop / sub_agent 处已知 conv_id,传入即可。旧两参签名内部转调 `store(.., None)` 兼容。 + +## 4. 风险与对策 + +| 风险 | 对策 | +|---|---| +| pin 滥用撑死池 | §3.4 降级规则 + pin 总量监控日志 | +| EvictionLog 内存增长 | 50 条上限 VecDeque,单条 ~200B,可忽略 | +| owner 传错 | 软隔离只影响淘汰顺序,不错即退回现状行为,无正确性风险 | +| 兼容 | 旧 store() 两参保留转调;EVICTED_PLACEHOLDER 文案仅在 Log 命中时升级,未命中原样 | + +## 5. 拍板点(2 项) + +- **拍板1**:pin 是否上限保护(pin 总量超 50% 降级最旧 pin)?建议加(防失控)。 +- **拍板2**:报告外的哪些工具产出默认 pin?建议本期**仅子代理报告**,其余观察后再加。 + +## 6. 工作量估算 + +约 0.5-1 天:entry 扩展+pin API(2h)+ EvictionLog(1.5h)+ owner 软隔离(1.5h)+ 两展开点富提示(1h)+ 单测(2h,现有 6 个 namespace 测试全保留+新增 pin/淘汰清单/隔离顺序 3 组)。 diff --git a/docs/02-架构设计/专项设计/u-relay-wire-protocol-2026-10-04.md b/docs/02-架构设计/专项设计/u-relay-wire-protocol-2026-10-04.md new file mode 100644 index 0000000..bbaec50 --- /dev/null +++ b/docs/02-架构设计/专项设计/u-relay-wire-protocol-2026-10-04.md @@ -0,0 +1,254 @@ +# u-relay Wire 协议规格(改造蓝本) + +> 版本:现行(第三代 agent/commander 命名,兼容层全拆) +> 来源:`E:/wk-lab/u-relay/src/{relay.rs, broadcast.rs, conn.rs}` + `README.md` +> 适用:df-tunnel / df-miniapp 升级对接 + +--- + +## 1. 拓扑与端点 + +``` +Commander(控制端) ──wss──> nginx(:443 TLS 终结) ──ws──> u-relay(:9180) + ↑ + Agent(执行端) ──wss 主动出站────────────────────────────┘ + (穿 NAT,无监听端口) +``` + +| 角色 | 端点 | 典型实现 | +|---|---|---| +| **Agent**(执行端,事件真相源) | `GET /ws/agent` | df-tunnel(桌面端)、u-claw runner | +| **Commander**(控制端,指令发起方) | `GET /ws/commander` | df-miniapp(小程序)、u-claw console、u-ppt | + +**端点即身份**:端点决定期望的 `ClientKind`,与 Hello.kind 不一致直接拒。 + +--- + +## 2. 握手协议 + +### 2.1 客户端首帧(10s 内必发,否则断开) + +```json +{ + "kind": "agent" | "commander", + "channel_id": "<非空, ≤128 字节, 无控制字符>", + "token": "" +} +``` + +| 字段 | 约束 | +|---|---| +| `kind` | 必须与端点匹配:`/ws/agent` 端点仅收 `"agent"`;`/ws/commander` 端点仅收 `"commander"` | +| `channel_id` | 配对绑定键;非空 + ≤128B + 无控制字符;同 channel_id 的 agent 与 commander 互为对端 | +| `token` | 服务端常量时间比较(防时序侧信道) | + +### 2.2 握手成功响应(relay 立即下发) + +```json +{ "kind": "control", "payload": { "control_kind": "hello_ack" } } +``` + +**客户端判定**:收到首条非 error 消息即握手通过(不要求对端在线)。 + +### 2.3 握手失败(relay 发错误帧后立即 Close) + +```json +{ "kind": "control", "error": "" } +``` + +| `error` 值 | 触发条件 | +|---|---| +| `handshake_failed` | 10s 未发 Hello / Hello JSON 解析失败 / 首帧非文本 / Hello 超 1 MiB | +| `kind_mismatch` | Hello.kind 与端点不匹配(如 agent 端点收 commander) | +| `invalid_channel_id` | channel_id 为空 / >128B / 含控制字符 | +| `server_misconfigured` | 服务端 `U_RELAY_TOKEN` 未设置 | +| `auth_failed` | token 不匹配 | + +### 2.4 已下线的旧值(一律拒绝) + +| 维度 | 现行 | 已下线(收到即拒) | +|---|---|---| +| 执行端端点 | `/ws/agent` | `/ws/runner` `/ws/device` `/ws/executor` | +| 控制端端点 | `/ws/commander` | `/ws/console` `/ws/miniapp` `/ws/controller` | +| Hello.kind 执行端 | `"agent"` | `"runner"` `"device"` `"executor"` | +| Hello.kind 控制端 | `"commander"` | `"console"` `"miniapp"` `"controller"` | +| 配对键字段 | `channel_id` | `device_id`(不再 alias) | +| 错误码 | `invalid_channel_id` | `invalid_device_id` | + +--- + +## 3. 数据帧(握手通过后) + +### 3.1 客户端 → relay(入站) + +入站文本帧即业务 payload,relay **不解析**直接透传: + +```json +{ "任意 JSON" } +``` + +非 JSON 文本会被包成 `{"payload": "<原字符串>"}`。 + +**特殊语义**:若 payload 顶层有 `control_kind: "ping"`,触发 relay 本地心跳响应(见 §4),不透传对端。 + +### 3.2 relay → 客户端(出站 BroadcastMessage) + +```json +{ + "channel_id": "chan-xxx", + "kind": "event" | "command" | "control", + "source": 12345, + "from": "agent" | "commander", + "payload": { "原始 JSON" }, + "ts": 1725000000000 +} +``` + +| 字段 | 说明 | +|---|---| +| `channel_id` | 配对通道 | +| `kind` | `event`=agent→commander;`command`=commander→agent;`control`=控制面 | +| `source` | 来源 conn_id(u64,0=NIL 伪值,relay 自构造消息用) | +| `from` | 来源客户端类型 | +| `payload` | 原始 JSON 透传 | +| `ts` | relay 收到入站帧的毫秒时间戳 | + +### 3.3 路由规则(relay 内部,客户端无需关心但需理解) + +| 消息 | 投递目标 | +|---|---| +| `Event`(agent 发) | 同 channel_id 的**所有 commander**(除来源自身) | +| `Command`(commander 发) | 同 channel_id 的**所有 agent**(除来源自身) | +| `Control` | 同 channel_id 的**所有连接**(除来源自身) | + +**方向硬约束**(relay 路由层强制): +- `Event` 永不投递给 agent +- `Command` 永不投递给 commander + +**多端登录**:同 channel_id 可并存多个 agent 和多个 commander,全投递(Vec 索引)。 + +### 3.4 帧限制 + +| 限制 | 值 | +|---|---| +| 入站文本帧 | **≤ 1 MiB**(含 Hello),超限直接断开 | +| 二进制帧 | **忽略**(MVP 仅文本) | +| WS Ping/Pong | 协议层自动处理(tungstenite),不进业务流 | + +--- + +## 4. 心跳协议 + +### 4.1 客户端发起 + +```json +{ "control_kind": "ping" } +``` + +**关键**:relay 收到后**本地直接回 pong**,不透传对端,也不依赖对端在线。 + +### 4.2 relay 响应 + +```json +{ + "kind": "control", + "from": "agent", + "source": 0, + "payload": { "control_kind": "pong" }, + "ts": 1725000000000 +} +``` + +**字段细节**: +- `source: 0` 是 `ConnId::NIL` 伪值 —— 若填接收方自己的 conn_id,路由防回环会跳过,pong 永远回不来 +- `from: "agent"` 是 relay 代理执行端身份 —— 让 commander 端识别为合法控制响应 + +### 4.3 客户端实现要点 + +| 端 | 用途 | +|---|---| +| **Commander** | 用 pong 更新 `lastPongTime`,看门狗超时则重连 | +| **Agent**(跑桌面/移动网络) | 用 pong 重置读死线,死线超时走既有重连 | + +--- + +## 5. 部署配置 + +### 5.1 环境变量 + +| 变量 | 默认 | 说明 | +|---|---|---| +| `U_RELAY_ADDR` | `0.0.0.0:8080` | 监听地址 | +| `U_RELAY_TOKEN` | **无(必填)** | 配对 token,未设置启动即 exit 1 | +| `RUST_LOG` | `info` | tracing env-filter | + +### 5.2 nginx 反代参考 + +```nginx +location /ws/ { + proxy_pass http://127.0.0.1:9180; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_read_timeout 300s; +} +``` + +### 5.3 部署形态 + +- **musl 静态编译**:`x86_64-unknown-linux-musl` → 单二进制 ~3.6MB +- **无 openssl/native-tls**:TLS 完全由 nginx 终结 +- **systemd 单元**:`/usr/local/bin/u-relay` + `/etc/u-relay.env`(权限 600) + +--- + +## 6. 客户端实现 Checklist + +### Agent(执行端,如 df-tunnel) +- [ ] 连 `wss://host/ws/agent` +- [ ] Hello `{kind:"agent", channel_id, token}` +- [ ] 等首条非 error 帧判定握手通过 +- [ ] 心跳:周期发 `{"control_kind":"ping"}`,等 pong 重置读死线 +- [ ] 入站 `BroadcastMessage`:仅处理 `kind=="command"`(来自 commander 的指令)和 `kind=="control"` +- [ ] 出站:业务事件 JSON 直接作为文本帧发送(relay 包成 `Event` 投递给 commander) + +### Commander(控制端,如 df-miniapp) +- [ ] 连 `wss://host/ws/commander` +- [ ] Hello `{kind:"commander", channel_id, token}` +- [ ] 等首条非 error 帧判定握手通过 +- [ ] 心跳:周期发 `{"control_kind":"ping"}`,等 pong 更新 `lastPongTime` 看门狗 +- [ ] 入站 `BroadcastMessage`:仅处理 `kind=="event"`(来自 agent 的事件)和 `kind=="control"` +- [ ] 出站:业务指令 JSON 直接作为文本帧发送(relay 包成 `Command` 投递给 agent) + +--- + +## 7. 离线语义 + +| 场景 | 行为 | +|---|---| +| 对端不在线时发消息 | relay **丢弃**(不缓存),debug 日志记录"广播无对端在线" | +| 客户端判断对端在线 | 通过 `PresenceState`(relay 不主动推送,由客户端心跳或业务层判活) | +| 重连 | 客户端指数退避自行实现(df-miniapp 已有 `reconnectBaseDelay`/`reconnectMaxDelay`) | + +--- + +## 8. 安全说明 + +- **token 常量时间比较**:relay 端实现,防时序侧信道 +- **channel_id 校验**:格式防御,无 per-channel token 绑定(Phase3 留) +- **风险**:单共享 token 下,持 token 者可声明任意 channel_id 冒充该通道 —— 生产部署需确保 token 不泄露 + +--- + +## 9. 与旧版 df-relay 协议差异速查 + +| 维度 | df-relay(已下线) | u-relay(现行) | +|---|---|---| +| 端点 | `/ws/device` `/ws/miniapp` | `/ws/agent` `/ws/commander` | +| Hello.kind | `"device"` `"miniapp"` | `"agent"` `"commander"` | +| 配对键 | `device_id` | `channel_id` | +| 心跳 pong | 由对端回(路径长) | relay 本地回(路径短) | +| 旧名兼容 | 多代别名 | **一律拒绝** | +| 错误码 | `invalid_device_id` | `invalid_channel_id` | +| 帧上限 | 无 | 1 MiB | +| token env | `DF_RELAY_TOKEN` | `U_RELAY_TOKEN` | diff --git a/docs/02-架构设计/专项设计/uclaw两侧勘察补全-2026-10-04.md b/docs/02-架构设计/专项设计/uclaw两侧勘察补全-2026-10-04.md new file mode 100644 index 0000000..6cc0567 --- /dev/null +++ b/docs/02-架构设计/专项设计/uclaw两侧勘察补全-2026-10-04.md @@ -0,0 +1,75 @@ +# u-claw 两侧细勘察补全(多轮会话锚定 + 协议漂移) + +> 2026-10-04 · 上游:[devflow集成u-claw-可行性研究-2026-09-28.md](./devflow集成u-claw-可行性研究-2026-09-28.md) 第六节待补槽位「u-claw 侧收尾:WS 渠道的多轮会话锚定细节(request_id↔chain 映射、会话持久化边界)」。 +> 勘察基线:u-claw HEAD 021a230(基线 d8dc003 后 18 提交)/ u-relay 现行源码 / u-ppt 参考实现未变。 +> 全部结论以源码为准(wsch.go 405 行全文 + chainpool.go + agentd.go + u-relay src)。 + +## 一、多轮会话锚定:channel 级单 chain 模型(结论定案) + +**WS 渠道不是 per-request 会话,是 channel 级单 chain 粘性会话**: + +``` +wsChannel (1:1) + └─ chain = NewSessionChain("ws", cwd, statePath, ...) // wsch.go:113 run() 启动时建一次 + ├─ TakeSummary() 每轮取摘要 → RenderWithSummary 注入下轮 prompt // process():224 + ├─ HandleWithResult(prompt, progressWatcher) // 常驻 claude -p 子进程 + └─ 会话自动连续(各轮 session_id 相同,无需 --resume) // agentd.go:6 注释 +``` + +- **request_id 仅是单次指令标识**(配对进度/结果帧),不映射 chain——所有 request_id 共享同一 chain 与同一 claude 进程 +- **上下文维持**:常驻进程各轮 session_id 相同(agentd.go:6),链层另有摘要注入(`TakeSummary`→`RenderWithSummary`)双保险;崩溃/超时后 `ensureAlive` 自动重启并 `--resume` 上次会话 ID 恢复(agentd.go:154) +- **持久化边界**:会话状态文件 `sessionStatePath("ws")`(exports.go:96,落 `~/.u-claw/sessions/`);会话 jsonl 落 claude 自己的项目目录(cwd 对应);**跨进程重启后上下文不丢**(--resume + 会话文件保留) +- **devflow 侧含义**:接入后 devflow 与 u-claw 的对话天然是**一条连续会话**(同一 channel_id 下所有 ask_uclaw 调用共享上下文)——多轮追问无需传会话 ID,但也意味着 devflow 内不同 devflow 会话若共用 channel_id 会互相污染上下文(见 §4 设计含义 D-2) + +## 二、协议漂移:可行性文档已过时(重要修正) + +2026-09-28 可行性文档记载 `/ws/device` + `{kind,device_id,token}` hello——**已漂移**,e8113c5「中继握手协议对齐服务端」重定义了角色: + +| 维度 | 可行性文档(9-28 记载) | 现行源码(10-04 实证) | +|---|---|---| +| 端点 | `/ws/device` / `/ws/miniapp` | **`/ws/agent`(执行端,u-claw 连此)** / **`/ws/commander`(控制端,devflow 连此)** | +| hello | `{kind, device_id, token}` | **`{kind:"commander", channel_id, token}`**(commander);agent 端 `{kind:"agent", channel_id, token}` | +| 帧路由 | Event→Miniapp / Command→Device | **Event(执行端发)→同 channel_id 全部 Commander;Command(控制端发)→同 channel_id 绑定的 Agent**(conn.rs:114, relay.rs:117-119) | +| 心跳 | ping/pong(relay 本地回) | 同款仍在:30s ping / 90s 读死线 / 写死线 10s(wsch.go:45-50;miniapp 侧同款) | +| 鉴权 | 全局共享 token(鉴权债) | **配对语义已改**:Commander 持 token 申请绑定 channel_id(broadcast.rs:138 `Pair{channel_id, token}`),Agent 端 token 校验;但 relay 侧仍是 env `U_RELAY_TOKEN` 单 token(relay.rs:9-10, main.rs:28 fail-fast),**per-channel token 未做**——鉴权债部分缩小 | + +**接入实施时必须按本节现行协议实现,不能照抄 9-28 文档或 u-ppt relay.ts 原样**(u-ppt 用的还是旧 Miniapp/Device 语义,需确认 u-ppt 是否已随 e8113c5 升级,若未升级则 u-ppt relay.ts 仅作 TS 结构参考、协议字段按本节改)。 + +## 三、执行语义与时限(新增已核实事实) + +- **串行 worker**:每 channel 一条串行 worker goroutine,reqCh 缓冲 4,满则**丢弃**由发起方重试(wsch.go:108-109)——devflow 侧需配超时重试与队列已满可感知的语义(当前协议无「已丢弃」回执,devflow 端只能在超时后重发) +- **单条指令硬超时 15min**(`wsExecTimeout`,wsch.go:38):超时 AbortRunning 杀进程、回「处理超时」结果、链保 session ID 下条 --resume 续跑——**devflow aichat 工具的 client 侧超时须 >15min 或对齐处理** +- **进度节流 2s**(progressWatcher,wsch.go:368):assistant text=阶段叙述+tool_use=当前动作,2s 节流回传——devflow 工具卡「流式」粒度即此(块级,非逐 token) +- **空闲超时链回收**:chainPool idle 后整链回收(杀 claude 进程 ~500MB),来消息 --resume 重建冷启动 ~7s(chainpool.go:1-7)——**devflow 侧期望「空闲后首次调用慢」为正常** +- **链池挤占语义**:槽满 LRU 挤最旧 idle 链,活跃链不挤;hardCap 全忙时拒绝建链返错(chainpool.go:100-128) + +## 四、devflow 侧接入设计含义(增量到第五节) + +- **D-1 工具卡流式**:ask_uclaw 工具卡可直接消费 agent_progress 帧(2s 块级)作流式显示,agent_result 全文为最终 tool result——零改造对齐 devflow 现有工具卡模式 +- **D-2 channel_id 策略**:单 chain 会话模型下,建议 devflow **per-conv 生成 channel_id**(如 `devflow-{conv_id}`)接入——每个 devflow 会话映射独立 u-claw chain,会话隔离天然成立;代价是 u-claw 侧 chainPool 槽位占用(max 上限与 LRU 挤占,见 chainpool.go),需确认 u-claw 侧 max 配置余量(当前 max 值未在本次勘察范围,实施前核 `~/.u-claw/u-claw.yml`) +- **D-3 超时对齐**:devflow ask_uclaw 客户端超时建议 16min(>15min 硬上限),超时即回失败;进度 2s 节流下客户端 watchdog 应容忍 30s+ 无 progress(u-claw 长任务中间可能无 assistant 输出) +- **D-4 队列满丢弃无回执**:reqCh 满时静默丢——devflow 侧在 15/16min 超时后重发(最多 2 次),并把「u-claw 渠道忙」文案明确给用户 +- **D-5 offline 语义**:relay 无离线缓存(9-28 已载),叠加本节串行+丢弃语义:**devflow 发送前可先发探活 ping**(30s 内无 pong 视为渠道不可达),不可达直接报「u-claw 离线」不进队列 + +## 五、接入实施批清单(更新版,覆盖 9-28 第五节) + +1. **协议实现(Rust 客户端)**:连 `/ws/commander`,hello `{kind:"commander", channel_id: devflow-{conv_id}, token}`,按本节协议处理 Event 帧(agent_progress/agent_result 按 request_id 配对)——**不照抄 u-ppt relay.ts 字段**,仅参考结构 +2. **工具注册**:`ask_uclaw(prompt)` → declare_tool!(Low/只读? 不,执行类 Medium),progress 帧接 ToolCard 流式,result 全文为 tool result +3. **配置页**:relay URL / channel 前缀 / token(keyring)——默认关 +4. **超时与重试**:客户端 16min 超时 + 2 次重试 + 发送前探活 ping +5. **可选 phase2**:消息渠道形态(u-claw 代言 aichat)/ 反向 MCP——维持 9-28 形态 2/3 描述 +6. ~~**u-ppt 核对**(实施前置小步)~~ ✅2026-10-04 已核:u-ppt relay.ts 65bae53(2026-10-01)已随 e8113c5 升级 commander/channel_id 协议——端点自动补全 `/ws/commander`(:39)/hello `{kind:'commander',channel_id,token}`(:135)/10s 握手看门狗+hello_ack(:127)/30s ping+15s pong(:33)/指数退避 1s→30s(:36)/agent_request|progress|result 按 request_id 分发(:158) 六项与 u-relay 现行源码一致。**relay.ts 可直接作参考实现**(去 deck/SEP 专有逻辑),devflow 接入是 commander 协议第二个实现,非首个 + +## 六、基线更新 + +``` +基线 HEAD(2026-10-04): + devflow 9216d4c u-relay e8113c5后现行(见 src) u-claw 021a230 u-ppt 待核 +漂移检查(下次):u-claw git log --oneline 021a230..HEAD;u-relay per-channel token 是否落地 +``` + +## 关联 + +- 上游:`devflow集成u-claw-可行性研究-2026-09-28.md`(本文件填其第六节末槽位) +- u-claw 源:`wsch.go`(WS 渠道全文 405 行)/ `internal/core/chainpool.go`(链池)/ `internal/core/agentd.go`(常驻 claude + --resume) +- u-relay 源:`src/relay.rs`(端点+握手)/ `src/conn.rs`(配对路由)/ `src/broadcast.rs`(Pair 协议) diff --git a/docs/02-架构设计/专项设计/子代理完成卡已消化降级-设计-2026-10-04.md b/docs/02-架构设计/专项设计/子代理完成卡已消化降级-设计-2026-10-04.md new file mode 100644 index 0000000..d1ee8cc --- /dev/null +++ b/docs/02-架构设计/专项设计/子代理完成卡已消化降级-设计-2026-10-04.md @@ -0,0 +1,97 @@ +# 子代理完成卡双轨「已消化」降级 · 设计(2026-10-04) + +> ✅ 拍板通过(2026-10-04,2/2 按建议:D1 自动折叠默认开/D2 trace 随 namespace 批;见 [拍板集](../滚动规范/拍板集-2026-10-04.md)) + +> 来源:todo.md 子代理深查「P2 完成卡(前端全文)与父上下文(压缩)双轨无『已消化』降级机制[需设计]」。 +> 勘察结论(2026-10-04 现场核实,以源码为准,**修正深查一处过时结论**): +> - 完成卡前端已非「重启蒸发」:`aiShared.ts:677` 已有按父 conv 经 `ai_sub_agent_list` 反查重建完成卡(轨迹存在即视为 completed),重启回补链路已通。剩余缺口即「已消化」降级。 +> - 双轨现状:前端卡持 summary 全文(`AgentFinishedCard.summary`,卡面 160 字截断展示);父上下文中报告经 namespace 引用+`context_helpers.rs` 视图压缩(`TOOL_RESULT_SUMMARIZE_BYTES=2048` / `TOOL_RESULT_JSON_STR_FIELD_MAX=512`),**父 LLM 后续轮次只能看到 ≤512 字符折叠摘要**。 +> - 事件链:`sub_agent.rs:495` 统一出口 emit `AiAgentFinished{status,summary,rounds,tokens,rejected_tools,stop_kind}`(挂父会话)+ 整轨迹落库(V44 origin='sub_agent')。 + +## 1. 问题定义 + +「双轨无降级」的三层含义: +1. **信息层**:父 LLM 与前端卡各持一份(上下文折叠摘要 vs 前端全文),两者无互认,用户在卡上看到的细节 LLM 答不上; +2. **生命周期层**:卡永久挂在消息流(直到会话删除),无「已读/已消化」状态;多轮追问后卡仍以初始完整态占据视觉焦点; +3. **一致性层**:父 LLM 被追问报告细节时若折叠摘要不够,唯一出路是重新 `ai_sub_agent_list` 反查轨迹(LLM 未必想到/舍得花 token)。 + +## 2. 设计目标 + +1. 卡可标记「已消化」,视觉降级(折叠/淡化)但**可展开复原**,信息不丢; +2. 父 LLM 追问细节时有**结构化自助通道**(不用重跑子代理); +3. 「已消化」状态**持久化**(重启/切会话后保留); +4. 零后端 schema 变更(复用现有落库轨迹)。 + +非目标:不做卡全文注入上下文(会反向膨胀 prompt);不做自动消化判定(何时算「消化」留人工,v2 可议 LLM 显式 ack)。 + +## 3. 方案 + +### 3.1 「已消化」状态与持久化 + +前端 `AgentFinishedCard` 增字段: +``` ++ digested?: boolean // 默认 false +``` + +持久化载体:**复用 KV 存储**(app 已有 settings/KV 表),key = `agentCardDigested:{parentConvId}` → `string[]`(agentId 列表,JSON)。切换/挂载回补时(aiShared.ts:677 重建路径)读 KV 合并标记。不落 SQLite 新列/新表——卡本身是派生态(由轨迹重建),消化标记是用户偏好,KV 语义足够。 + +### 3.2 视觉降级交互 + +``` +未消化卡: 现状(标题行+status 徽章+160 字摘要+展开全文) +已消化卡: 标题行单行化(✓ 已消化 · summary 首 40 字 · status 徽章淡化),点击展开复原全文 +手动标记: 卡右上角「标记已消化」动作(hover 显现),支持批量(同会话多卡) +自动辅助: 同会话出现新完成卡时,旧未消化卡自动折叠为单行(不标已消化,仅视觉收纳,复用 ToolCardList 分组折叠的 touched 语义——用户手动展开过则不自动收) +``` + +### 3.3 父 LLM 自助通道(关键补强) + +现状 LLM 有 `ai_sub_agent_list`(列轨迹元数据)但**没有读单条轨迹全文的工具**(前端卡经 IPC `ai_sub_agent_list` 拉的是轨迹列表,LLM 侧工具面无对应读全文入口)。 + +新增 LLM 工具(注册进 tool_registry,risk=Low 只读): +``` +ai_sub_agent_trace(conversation_id, agent_id) -> { summary, status, rounds, tokens, messages_tail? } +``` +- 返回该子代理轨迹的关键内容(summary 全文 + 末 N 条消息摘要),**只读、走现有 V44 落库数据**,零新存储; +- system prompt 子代理指引段补一句:「追问子代理产出细节时,先调 ai_sub_agent_trace 而非重新 spawn」; +- 这同时是 namespace 淘汰治理( sister 设计文档)中「报告蒸发死路」的兜底——即使 namespace 条目被淘,轨迹在 DB,工具可读。 + +### 3.4 「已消化」与上下文压缩的联动(可选增强,默认关) + +`AgentFinishedCard.digested=true` 时,前端在后续轮次注入的用户消息尾部不加任何内容(保持零侵入);该标记仅影响 UI 与用户心智。**不**把 digested 同步回后端压缩策略(避免跨端状态同步复杂度)。 + +## 4. 改动面清单 + +| 层 | 文件 | 改动 | +|---|---|---| +| 前端 | `src/composables/ai/aiShared.ts` | AgentFinishedCard+digested;重建路径读 KV 合并 | +| 前端 | 完成卡渲染组件(MessageList 内 SubAgentCard 或同域) | 降级态渲染+标记动作+批量 | +| 前端 | KV 读写封装(复用现有 settings composable) | get/set `agentCardDigested:{convId}` | +| 后端 | `src-tauri/src/commands/ai/agentic/sub_agent.rs` | 暴露 ai_sub_agent_trace IPC(读库组装) | +| 后端 | `tool_registry.rs` | 注册 ai_sub_agent_trace(Low/只读白名单) | +| 提示词 | system prompt 子代理指引段 | 追问先 trace 不重跑 | + +## 5. 风险与对策 + +| 风险 | 对策 | +|---|---| +| KV 标记与轨迹删除不同步(轨迹删了 KV 残留) | 重建路径只对「轨迹存在的卡」应用标记,孤儿 key 自然失效,无需清理任务 | +| trace 工具被滥用(LLM 反复查大轨迹) | 返回体加尾部分页/上限(messages_tail ≤ 20 条),复用 T-05 工具结果截断口径 | +| 卡交互改动碰 MessageList 渲染热点 | 卡是独立组件,降级态纯展示层,vue-tsc+手测三态(未消化/已消化/展开) | + +## 6. 验收 + +1. 标记已消化 → 卡单行化 → 重启应用后仍单行(KV 持久); +2. 展开已消化卡 → 全文复原; +3. LLM 调 ai_sub_agent_trace 能返回指定子代理 summary 全文; +4. 未做任何标记的会话,渲染与现状逐像素一致(回归门); +5. cargo test(新增 trace IPC 组装单测)+ vue-tsc 0 error。 + +## 7. 拍板点(2 项) + +- **拍板1**:旧卡自动折叠(§3.2)默认开还是关?建议开( touched 语义保护手动展开)。 +- **拍板2**:ai_sub_agent_trace 本期做还是随 namespace 治理批一起做?建议**随 namespace 批**(同域文件+互为兜底)。 + +## 8. 工作量估算 + +约 1-1.5 天:digested+KV(2h)+ 卡降级渲染(3h)+ trace IPC+注册(3h)+ 提示词(0.5h)+ 测试(2h)。 diff --git a/docs/02-架构设计/专项设计/无人值守长任务-设计-2026-10-04.md b/docs/02-架构设计/专项设计/无人值守长任务-设计-2026-10-04.md new file mode 100644 index 0000000..e8d81dd --- /dev/null +++ b/docs/02-架构设计/专项设计/无人值守长任务-设计-2026-10-04.md @@ -0,0 +1,318 @@ +# 无人值守长任务 — 机制设计 + +> 日期: 2026-10-04 | 状态: ~~设计稿(待拍板)~~ ✅拍板通过(2026-10-04,13/13 按建议;全量拍板记录见 [拍板集-2026-10-04.md](./滚动规范/拍板集-2026-10-04.md)) | 勘察: 只读实测锚点 +> 拍板背景: 产品方向定为「任务规划一次性确定边界后,无人值守、自主无干预、稳定完成长任务」;S2-B 真审批通道延后不做。 +> 设计目标(用户原话转译): ①长任务中途零打断(不弹审批、不等人) ②发起时一次拍板授权范围,存续期内 AI 全自主 ③无人盯着也能信任——失败自愈、进度可观测、异常安全停靠、完成/异常有通知。 + +--- + +## 一、现状勘察(锚点实测) + +### 1.1 打断点全景与无人值守处置 + +| # | 打断点 | 现状机制(锚点) | 现行为 | 无人值守处置 | +|---|--------|---------------|--------|-------------| +| 1 | 风险审批挂起 | `audit/approval.rs` handle_approval_tool → insert_pending_approval;auto_exec_mode 三档(low/medium/all) + patch_file 全档放行特例 + 会话信任(session_trust,`mod.rs:542` TrustKey) | Medium/High 挂 loop,弹卡 + 系统通知,默认 15 分钟超时自动取消(`state.rs:240` approval_timeout_minutes) | **边界内放行**:风险≤任务上限 ∧ 非破坏性命令 → 直接执行(decided_by=boundary_auto);边界外不弹卡,拒绝 tool_result + 记待办 | +| 2 | 路径授权挂起 | `audit/path_auth.rs` check_file_tool_auth → NeedsAuth → ApprovalKind::Path + emit AiDirAuthRequired | 挂 loop 等三档授权(once/session/always,`state/allowed_dirs.rs`) | **边界内放行**:路径命中任务白名单 → Authorized;白名单外 → 不弹卡,结构化拒绝(L1 可改提示) | +| 3 | 黑名单硬拒 | 同上 Denied 分支 + validate_path 黑名单;已有先例:all 档保黑名单(audit/mod.rs:667),bypass 开关才连黑名单放行(PathBypass::All),子代理 KeepBlacklist | 就地拒绝,loop 继续 | **永不放行**(安全底线,同 all 档/子代理先例);拒绝 envelope 提示换路径 | +| 4 | 破坏性命令 | `mod.rs:603` is_destructive_command(rm/del/format/... 首 token 精配) | 信任放行门控,命中走正常审批 | **永不放行**;边界内 run_command 也过此闸 | +| 5 | LLM 流错误停 | `agentic/mod.rs` RoundOutcome::Fatal(候选 4xx 非429 或全 candidate 耗尽)→ return;流前 InitFailed Retryable 已有退避重试+candidate 链切换(retry.rs 同源分类) | Fatal 直接终轮 | **降级为安全停靠**(见 4.2):非正常终局统一停靠出口,不再裸 return | +| 6 | 工具执行失败 | Low 失败 = 失败 envelope 进 tool_result,loop 继续(AR-6);外层超时 60s/run_command clamp/spawn_agent 挂钟+60 | 错误交 LLM 自纠 | **可降级继续**:已有,不改;唯一化入停靠判定(连续失败见 4.1) | +| 7 | 断路器求助 | L1 失败断路器(THRESHOLD=3/WINDOW=20)+ G2 探索熔断(3 次) → emit 求助,等用户 | 挂起等介入 | **安全停靠**:触发即停靠(保留熔断,语义从「等」改「存档+通知」) | +| 8 | 达最大轮次 | agentic/mod.rs:1150 已改自动收尾(incomplete=true)+ NeedAction 通知 | 自动终止 | **已是停靠雏形**,补停靠说明+待办清单,预算可由任务边界放大 | + +结论:打断点 1/2 是无人值守的**主要敌人**(挂起等输入);3/4 是**安全线**(保留);5-8 已有自动终局雏形,统一成语义即可。 + +### 1.2 既有边界件盘点(可直接复用为任务级边界底座) + +| 件 | 锚点 | 复用方式 | +|----|------|---------| +| spawn_agent 白名单钳制 | `agentic/sub_agent.rs:260` clamp_tool_whitelist(tools ∩ Low ∖ spawn_agent)+ 执行期双闸(audit/mod.rs:172 sub_agent_tool_clamped) | 判定结构参照;**子代理不放宽**(fail-closed 保持,见拍板点 6) | +| 会话级授权目录 | `state/allowed_dirs.rs` AllowedDirs{persistent/session/once} | 任务白名单独立于三档(任务级,不写用户 persistent 白名单——一次性授权不污染全局);判定函数复用 check_path_authorization 的规范化/黑名单逻辑 | +| 三重熔断 | `sub_agent.rs:301` round_budget_stop(轮次/200k token/900s 挂钟) | 结构直接抄给任务级预算(参数独立可配,主会话量级上限实测后定) | +| 看门狗/心跳 | execute_with_heartbeat 30s AiHeartbeat + 前端 130s watchdog + stall_detector check_retry_exhausted | 已覆盖长工具误杀与流断连,零改动 | +| fail-closed 拒绝协议 | deny_sub_agent_tool 结构化 envelope(denial_layer 四层)+ is_sub_agent_deny_envelope 解析 | 边界外拒绝**照抄此协议**(新 denial_layer=boundary-exceeded),LLM 可自纠、报告可申报缺口 | +| 审批恢复/落库 | pending_approvals 序列化 + restore_pending_approvals 启动恢复;auto checkpoint(save_conversation 每 20 条消息 <1MB 快照入 ai_conversation_checkpoints) | 断点续跑底座(P2) | +| 全局全自动先例 | df-ai-auto-execute-mode=all + df-ai-path-auth-bypass | 即「完全信任」档的存量实现(L3 远期档,见五);本设计不重造 | + +### 1.3 稳定性现状 + +- 重试面: retry.rs 指数退避(1s→2s→4s+jitter,30s 预算,Retryable/Fatal 分类)覆盖 complete() 与流前;candidate 链自动切 provider。**工具级无自动重试**——被 detect_retry_count/去重缓存刻意压制(防死循环),维持。 +- 进度可观测: AiToolCallStarted/Completed 全事件流 + AiHeartbeat + 审计表 + checkpoint。缺「任务级」聚合视图(轮次/预算余量)。 +- 通知: `notify.rs` 三类(Completed/Failed/NeedAction),主窗聚焦跳过 + 5s 节流合并 + 失败静默。P3-6 基建完整,停靠/完成通知直接挂现有出口。 +- 断点续跑: checkpoint 表有快照、审批有启动恢复,但 **loop 本身重启后不自动续跑**,需人工。 + +--- + +## 二、任务级授权边界模型 + +### 2.1 数据结构(挂会话,不建新表——宁少勿预留) + +```rust +// commands/ai/boundary.rs(新文件,纯结构+判定函数+单测) +pub struct TaskBoundary { + pub risk_ceiling: RiskLevel, // 上限 Low|Medium;High 不经此通道(拍板点 1) + pub allowed_dirs: Vec, // 任务目录白名单(canonicalize 规范形态,含项目根) + pub forbid_destructive: bool, // 恒 true,字段留作显式声明(UI 展示用),判定不读 + pub budget: TaskBudget { max_rounds: u32, max_tokens: u64, wall_secs: u64 }, // 缺省继承现网常量 +} +``` + +存储与生命周期: +- 内存: per_conv 会话条目新增 `boundary: Option`(会话级单真相源先例,`mod.rs:621`); +- 落库: ai_conversations 新列 `boundary_json`(迁移一个 ALTER TABLE,save_conversation 随现有 meta 链路写,启动 load 还原); +- 生命周期 = 会话存续: 发起时一次声明 → 整个任务存续生效 → 会话删除级联消失。不做中途改边界(改边界=新拍板,UI 提示重开任务),防「边跑边扩权」; +- 与全局档正交: 有 boundary 的会话 boundary 优先;无 boundary = 现状逐次审批,**渐进增强零倒退**。 + +### 2.2 UI 形态(发起时一次性配置卡) + +参照 spawn_agent 参数卡(审批卡 approval_hint 模板,`tools/spawn_agent.rs:172`)+ 设置页范式: +- 入口: 新任务发起对话框(或首条消息发送时)展开「无人值守边界」折叠卡;非必填——不展开 = 现状审批模式; +- 字段四项: 风险上限(Low/medium 单选,默认 Low)/ 目录白名单(复用设置页 allowed_dirs 目录选择交互,默认预填当前项目绑定目录)/ 预算(轮次/token/挂钟,默认值预填,高级折叠)/ 确认按钮文案「一次授权,任务期内不再打扰」; +- 展示态: 任务进行中侧栏会话条目挂边界徽标,点开只读回显(禁中途改)。 + +### 2.3 IPC 面 + +`ai_set_task_boundary(conv_id, boundary_json)` 发起时调用;`ai_get_task_boundary(conv_id)` 回显。删除/停止会话既有级联不动(边界随会话条目同亡,无需新清理点)。 + +--- + +## 三、边界内审批旁路(risk 分流改造) + +### 3.1 判定链插桩(单点,两处) + +现判定链: path_auth 预校验(path_auth.rs)→ classify_risk_and_auto(approval.rs:33)→ trust → pending。改造在 `process_tool_calls`(audit/mod.rs:604)读取 auto_exec_mode 处并列读取 boundary 快照,然后: + +``` +对每条工具调用(有 boundary 会话): + ① 黑名单命中 → Denied(现状,永不放行) + ② 文件工具: 路径 ∈ boundary.allowed_dirs → Authorized; + 路径 ∉ 白名单 → 拒绝 envelope{denial_layer:"boundary-dirs"},不弹卡不挂起, + LLM 换路径或写入报告未尽事项(fail-closed 同构) + ③ 风险: risk ≤ risk_ceiling ∧ (run_command → !is_destructive_command) + → 归入 low_risk 并行执行向量(复用既有执行+审计链), + decided_by = "boundary_auto"(risk 真实等级透传,F-#97 先例防审计失真) + ④ 超上限(含 High、破坏性命令) → 拒绝 envelope{denial_layer:"boundary-risk"}, + 记入会话待办清单(4.3),不 insert pending +``` + +### 3.2 兼容性(不倒退保证) + +- 无 boundary 声明: 上述分支全部跳过,auto_exec_mode/trust/审批/路径授权全链路现状,零行为变更; +- ai_approve / ai_authorize_dir IPC 不动: 有边界会话不产生新 pending(黑名单本来也不产生),审批 UI 自然不触发; +- 审批超时定时器(15 分钟)对边界会话天然不触发(无新挂起),零改动; +- PathBypass 枚举不加新形态: 边界会话白名单判定在 check_file_tool_auth **调用前**完成(boundary 命中即 Authorized,bypass 参数传 Off 保黑名单),避免与 bypass 开关语义纠缠; +- 审计: boundary_auto / boundary-dirs / boundary-risk 三种 decided_by/denial_layer 全留痕,无人值守事后可全量追溯。 + +--- + +## 四、无人值守稳定性机制 + +### 4.1 失败分级自愈(增量最小化) + +| 级别 | 判定 | 处置 | 增量 | +|------|------|------|------| +| 瞬态可重试 | 网络超时/5xx/429(复用 retry::is_status_retryable) | 已有: 退避重试+candidate 链,零改动 | 无 | +| 工具级失败 | 失败 envelope | 已有: 交 LLM 自纠(loop 继续),死循环已被去重缓存+retry guard 治理 | 无 | +| 探索停滞 | L1/G2 断路器触发 | 改: 熔断求助出口 → 安全停靠(4.2) | 小 | +| 不可恢复 | Fatal 全 candidate 耗尽 / 边界预算耗尽 / 连续 N 轮零产出(阈值实测后定) | 统一安全停靠出口 | 中 | + +不新造工具级自动重试层——既有 envelope+熔断已覆盖,自动重试同参数正是 detect_retry_count 刻意压制的行为(反馈_no_guess_api 同源: 盲重试制造风暴)。 + +### 4.2 安全停靠语义(不是死等) + +现网「非正常终局」五路出口(Fatal/Stale/MidStream/熔断/达轮次)行为不一。统一停靠出口: + +1. 保存现场: 既有 teardown_round 落库链路不变; +2. 会话尾部追加停靠说明(system 提示块): 停止原因 / 已完成什么(取本轮 assistant 文本) / **待办清单**(边界外被拒操作 + 未完成事项,数据源=3.1④ 的拒绝记录 + 熔断采样); +3. emit `AiTaskParked { conv_id, reason, pending_items }` 新事件(前端操作卡: 继续恢复/停止归档,复用 pendingMaxRounds 操作卡骨架——lib.rs:435 既有续/停 IPC); +4. notify NeedAction 系统通知(托盘场景补位,复用 P3-6 全套); +5. **不保持 generating=true**: guard 复位(达轮次出口已有先例),用户回来点「继续」走 ai_continue_loop(start_iter 语义沿用: 预算耗尽重计=用户再授权)。 + +### 4.3 进度可观测 + +- 已有零改动: 工具事件流 + 心跳 + 审计表即事实源; +- 增量: 每 N 轮(建议 5,实测后定)emit `AiTaskProgress { conv_id, round, budget, tokens_used, pending_items_count }`;前端会话头部挂轻量进度条(轮次/预算维度),长任务静默期(如 spawn_agent 子代理长跑)用户可判断「在干活还是死了」。不落新表,事件即逝。 + +### 4.4 完成与异常通知 + +复用 notify.rs 现有三类出口,无需新通知通道;增量仅两处挂点: 停靠出口(4.2)发 NeedAction、边界会话正常收敛发 Completed(emit_ai_completed_once 已挂,核对边界会话不因 incomplete 路径漏发即可)。 + +### 4.5 断点续跑(P2,进程重启后) + +- 现状: checkpoint 快照已有、pending_approvals 有启动恢复,loop 不自动续; +- 设计: ai_conversations 新列 `loop_state`(running/parked/finished),边界会话 loop 生命周期同步落库;启动时检测「loop_state=running 但进程重启」→ **不自动续跑**(本地桌面场景,重启即用户在场,自动续跑反而惊吓),侧栏该会话标「任务中断可恢复」+ 一键恢复按钮; +- V21 迁移教训直接套用(docs/todo.md:860: 全局 COUNT 幂等窗口,中途崩溃→永久残缺被版本号掩盖): 恢复判据必须**按会话逐条落进度标记**(loop_state per-conv),禁止依赖全局内存态或推算;快照恢复走既有 checkpoint 表,恢复粒度=消息级(本轮已落库消息不重放,ai_messages 增量基线既有机制天然支持)。 + +--- + +## 五、信任分级(拍板项) + +| 档 | 语义 | 载体 | 状态 | +|----|------|------|------| +| L1 逐次审批 | 现状: 三档 auto + 审批卡 + 路径授权弹窗 | df-ai-auto-execute-mode | 现网,不动 | +| L2 任务边界自主 | 本设计主体: 发起时一次拍板,边界内零打断,黑名单/破坏性命令永不放行 | TaskBoundary(会话级) | 本设计 P0 | +| L3 完全信任 | 等价 skip-permissions: 全档自动+连黑名单也放行 | 存量组合: auto=all + path-auth-bypass=on | 远期可选,UI 不与 L2 并列推荐,标注「含敏感目录」风险;不新造代码 | + +分级关系: L2 是 L1 之上的会话级增强,L3 是全局级现状开关的组合,三层互不替代。 + +--- + +## 六、分期实施建议 + +### P0 边界模型 + 旁路主干(可独立交付验收) +- 改动面: 新增 `commands/ai/boundary.rs`(结构+判定+单测)、`commands/ai/mod.rs`(per_conv 字段+IPC 注册)、`conversation.rs`(boundary_json 落库列)、`audit/mod.rs`(判定链插桩:auto_exec_mode 读取处)、`audit/path_auth.rs`(boundary 白名单判定前置)、`audit/approval.rs`(boundary_auto 分流)、迁移一条(boundary_json 列)、前端任务发起配置卡 + useAiConversations 透传; +- 验收: 边界会话 Medium 工具/白名单路径零弹卡直接执行+审计 boundary_auto;黑名单/破坏性命令/超上限三项被拒且不弹卡;无边界会话全链路行为与改造前逐字节一致(既有测试全绿); +- 冲突面: audit/mod.rs、approval.rs、path_auth.rs、conversation.rs、chat.rs、state.rs **全部在当前在飞批次工作区改动中**(git status 30+ 文件,befix2/dx1/dx2 三代理在改)——P0 必须等在飞批次合入后开工,或以 worktree 零交集摘出纯新增文件(boundary.rs+前端卡)先行、插桩点后置。串行,禁双头互踩(uswitch-403 同款事故预防)。 + +### P1 自愈 + 通知(依赖 P0 边界字段) +- 改动面: `agentic/mod.rs`(五路非正常终局统一停靠出口)、`stall_detector.rs`(熔断求助→停靠)、`notify.rs` 挂点、event_bus 新事件 AiTaskParked/AiTaskProgress、前端操作卡+进度条; +- 验收: 构造 Fatal/熔断/预算耗尽三种场景 → 各自产停靠说明+待办清单+托盘通知,generating 复位,点继续可续跑; +- 冲突面: agentic/mod.rs 在飞改动中,同 P0 策略。 + +### P2 断点续跑 + 信任分级(依赖 P1 停靠语义) +- 改动面: `conversation.rs`(loop_state 列+落库点)、`lib.rs`(启动扫描)、侧栏恢复入口;信任分级 UI 是否进设置页等拍板点 7; +- 验收: 边界会话长任务跑一半杀进程重启 → 侧栏标「可恢复」→ 一键恢复从 checkpoint 续跑不重放已落库轮次; +- 冲突面: lib.rs 启动段低频改动,冲突小。 + +--- + +## 拍板点清单 + +| # | 决策 | 选项 | 建议 | +|---|------|------|------| +| 1 | risk_ceiling 是否开放 High | A 封顶 Medium;B 开放 High 但破坏性命令仍拒 | **A**。High(run_command 等)无人看过命令串风险不可控;确需 High 归 L3 完全信任档 | +| 2 | 边界存储形态 | A 会话级 JSON 列;B 独立任务表 | **A**。任务与会话 1:1,独立表是过度设计;字段随会话同亡零清理成本 | +| 3 | 边界外动作处置 | A 拒绝+记待办随停靠报告;B 拒绝即停靠;C 弹卡(违背无人值守) | **A**。fail-closed 同构子代理,LLM 有自纠空间,缺口随停靠说明透出 | +| 4 | 进度事件频率 | A 每 5 轮;B 每轮;C 不做 | **A**。B 噪音,C 牺牲静默期可观测;具体值实测后定 | +| 5 | 重启后自动续跑 | A 不自动,标记+一键恢复;B 自动续跑 | **A**。本地桌面重启即用户在场,自动续跑惊吓且 V21 教训表明恢复判据须可人工确认 | +| 6 | 边界会话内子代理是否放宽 | A 维持 Low-only fail-closed;B 继承父边界 | **A**。子代理无监督面,放宽破坏隔离语义;Medium 需求由父会话边界内直接执行 | +| 7 | L3 完全信任是否进设置页 UI | A 不做 UI,文档说明存量开关组合;B 设置页显式三档 | **A(P2 再议 B)**。存量开关已可达,先验证 L2 使用率 | +| 8 | 中途改边界 | A 全不可改;B risk/目录不可改,预算可由用户中途调 | **B(补遗后修订)**。一次性拍板约束的是「AI 不回头问用户」,不是「用户不能动自己的任务」;risk 上限与目录白名单一次性不可改(安全边界),预算字段开放用户中途收紧/放宽(经 #12);**纠偏注入(7.2)≠改边界**——只注入指令文本,边界字段零触碰 | + +--- + +## 补遗(2026-10-04 二次拍板追加,与主体章节并列生效) + +> 追加两维:效率(任务完成得快、tokens 高效)与可观测/可控。不重写主体章节,冲突处以本补遗为准。 + +## 七、效率维度 + +### 7.1 token 效率(复用为主,增量小) + +| 设计点 | 既有件(复用) | 无人值守增量 | +|--------|--------------|-------------| +| 上下文膨胀控制 | ContextManager::build_for_request 预算裁剪;namespace_store 大工具结果进 namespace 主队列留引用(audit/mod.rs 两处 T2);TOOL_RESULT_COMPRESS_ENABLED 工具结果压缩;TOPIC_MARKER 话题标记;自动 checkpoint | 长任务场景将「工具结果冗余」放大,既有链路已按预算自动收敛,**零新增**;视图裁剪滚动摘要(派工决策单 B2 待做)落地后收益直接作用于长任务,不另立项 | +| 重复调用抑制 | 只读工具跨轮缓存+轮内去重(audit/mod.rs:976+,cache_hit_warning 递增威慑);High 去重缓存;detect_retry_count 断重试循环;G2 探索熔断(同签名重复派发检测) | **自动降级**:缓存命中计数达阈值(现警告头已有,阈值实测后定)时自动插入一条 system 降级指令(「同参调用已 N 次,必须换策略或写入报告」),把「威慑」升级为「强制转向」;G2 熔断在无人值守下直接走安全停靠(4.1 已定),不再等用户 | +| 任务级模型分级 | router ModelTier(Code/Debug→Heavy/Chat→Fast,agentic/mod.rs:1617 tier tiebreak);resolve_model_with_override;spawn_agent 的 model 参数(子代理可指定模型) | 边界配置卡加可选「子代理模型」高级项;**默认策略: 子代理派发缺省走轻量模型**(重活主循环继承会话模型,机械探索活子代理小模型),路由复用 ModelTier 既有分档,零新机制(#10) | +| prompt 瘦身/任务书复用 | spawn_agent 任务书自包含语义(子代理看不到父对话,不重复注入父轨迹);GOAL_PIN 钉目标防逐轮重述(GOAL_INJECT_BANNER);SKILL_LIST 描述截断 80 字 | 零新增——「任务书复用而非重注入」正是子代理架构的既有形态;长任务多轮目标防漂移由 GOAL_PIN 覆盖 | + +### 7.2 速度设计点 + +| 设计点 | 机制 | 与既有的关系 | +|--------|------|-------------| +| 并行工具批最大化 | 旁路后 Medium 工具归入 low_risk 向量走 join_all 并行(§3.1③) | **本设计免费提速点**:现网 spawn_agent(Medium)逐个走审批串行挂起;边界会话内 LLM 一轮发多个 spawn_agent → join_all 天然并行,上限 MAX_TOOL_CALLS_PER_ROUND=8。**P0 零代码副产品,须在验收清单标注** | +| 子代理并行编排 | 同上——并行编排不需要新调度器,是「旁路 × join_all」的组合效应 | 零新增;子代理各自独立预算熔断(三重熔断互不挤占),父侧只等 join_all 汇合 | +| 空轮/确认轮消除 | 无人值守任务书模板追加一条纪律:「不向用户提问;信息不足按明确假设继续,假设写入报告」;纯文本收敛轮(无 tool_calls)即终态,不存在「等确认轮」 | 复用 PURE_GREETING_TOOL_GATE 与 G2 熔断兜底异常空转;确认类行为在无人值守下=fail-closed 反面(挂起等输入),任务书纪律+边界语义双重压制,P0 随配置卡文案交付 | + +### 7.3 效率度量口径(为「快」提供数据) + +- **任务耗时** = 首条 user 消息 → 终态事件(AiTaskParked / 正常收敛)的挂钟差;落库复用 ai_conversations.created_at + 终态时间戳(补 parked_at 小列或复用 updated_at,P0 定); +- **token 花费** = 会话累计 prompt/completion 列(已有,save_conversation 落库)+ **子代理单列**(SubAgentOutcome rounds/tokens 已经 AiAgentFinished 透出;子代理出口整轨迹落库但 token 不进父 TokenAccumulator,故口径必须「父会话 / 子代理 / 合计」三段呈现,禁混算,#11); +- **每轮均摊** = 合计 token / 轮次(趋势指标,识别哪段任务烧钱);不做成本换算(密钥价目不进引擎,数据不出门边界)。 + +**分期归属**: 并行编排/确认轮消除/度量口径落库=P0(大部分零代码或小列);缓存降级注入+子代理默认小模型=P1;度量面板汇总视图=P2(随可观测面板同批)。 + +## 八、可观测/可控维度 + +### 8.1 可观测(10 秒三问:跑到哪/花多少/剩多少) + +| 呈面 | 数据源(复用) | 新增量 | +|------|--------------|--------| +| 当前进度呈面(阶段/当前动作/轮次与 token/预算剩余) | 当前动作=最近一条 AiToolCallStarted 的 tool+GoalMeta 摘要(goal_of 已有,如 run_command→「执行 xxx」);轮次/token=AiTaskProgress 事件(§4.3 已设计) | 会话头部常驻任务面板(#12):一行「阶段·当前动作」+进度条(轮次/预算)+token 累计;打开界面即答三问,不依赖滚动消息流 | +| 子代理树状态一览 | SubAgentRegistry(parent→children 内存注册表,已有)+ AiAgentFinished(每子代理终态 rounds/tokens/rejected 已透出) | 树 UI 为纯前端消费:运行中子代理=spawn 事件实时挂节点,完成=Finished 回填终态;父会话面板内嵌一行树,不建独立页面 | +| 花费实时累计 | TokenAccumulator 快照 + usage_delta_since 增量口径(均已有) | AiTaskProgress 携带 tokens_used 即可,零新事件 | + +### 8.2 可控(逐项标注复用/新建) + +| 操作 | 机制 | 复用 or 新建 | +|------|------|-------------| +| 中途停止 | ai_chat_stop → stop_flag 置位 + cascade_stop_children(Stop form)级联子代理 | **纯复用**,零改动;边界会话停止=任务终止,停靠说明照发(4.2) | +| 暂停/恢复 | 「停止 + 一键恢复」组合即暂停:stop 保现场落库,恢复走 P2 断点续跑入口(ai_continue_loop, checkpoint 粒度) | **复用组合,不新造「暂停态」**(宁少勿预留——独立暂停态需新增 loop 挂起检查点,收益不抵复杂度);P2 交付 | +| 中途纠偏(向运行中任务注入指令) | ai_chat_force_send 既有通道:打断当前轮 + 注入新 user 指令 + F1 并发 epoch 新 loop 接管(旧 loop 让位,epoch 机制已有)+ 级联 Stop form 子代理 | **纯复用**;语义定义:纠偏只注入指令文本,边界字段零触碰(**纠偏≠改边界**,与拍板点 8 对齐);P0 即可用,任务面板加「插话」入口即可(前端小改) | +| 接管转人工 | = 任务终止的单向形态:用户纠偏注入「停下我来」或点停止 → 移除 boundary 标记,会话回落 L1 逐次审批模式继续对话 | **复用 stop + boundary 摘除**;单向降级(任务态→普通态)不是边界修改,不违反拍板点 8;P1 随停靠操作卡交付「转人工」按钮 | +| 预算中途调整 | IPC ai_update_task_boundary 仅开放 budget 三字段(轮次/token/挂钟),risk/目录拒改 | **新建一个窄 IPC**(P1);用户主动调整合规(拍板点 8 修订后口径),UI 在任务面板预算条旁放开编辑 | +| 与看门狗/级联取消的关系 | 纠偏/接管经 epoch 接管不与前端 watchdog 冲突(新 loop 自带 guard+heartbeat);级联取消(Stop/Delete 双形态)覆盖停止与删除两路 | 既有机制全覆盖,零新增 | + +**分期归属**: 中途停止/纠偏注入=P0(复用件,仅前端入口);任务面板+子代理树+预算调整+接管=P1;暂停/恢复=P2(与断点续跑同批,共享恢复入口)。 + +## 补遗新增拍板点(续编) + +| # | 决策 | 选项 | 建议 | +|---|------|------|------| +| 9 | 缓存命中的自动降级策略 | A 命中超阈值自动插 system 强制转向指令;B 维持警告头威慑 | **A**。无人值守无人读警告,机制必须自己踩刹车;阈值实测后定 | +| 10 | 任务级模型分级默认 | A 边界卡显式选;B 子代理默认轻量模型+主循环继承会话模型,卡内高级项可覆盖;C 不做 | **B**。自动分级零配置收益最大,显式选择作兜底;轻量模型具体指认实测后定 | +| 11 | token 度量口径 | A 父会话/子代理分列+合计;B 只算父会话 | **A**。子代理 token 不进父 TokenAccumulator,混算会严重低估;合计是「任务花费」的正口径 | +| 12 | 任务面板形态 | A 会话头部常驻面板(进度+花费+预算+插话+树);B 仅侧栏徽标点开看 | **A**。「10 秒三问」要求免点击可达;徽标作为托盘化场景补充 | +| 13 | 预算中途调整方向 | A 双向(收紧/放宽)都允许;B 只许收紧 | **A**。用户主动放宽=追加授权,与「一次性拍板」不冲突(拍板约束 AI 不约束用户) | + +## 九、效率补遗二:u-claw 实战思想迁移(2026-10-04,历史会话汲取) + +> 来源:`~/.u-claw/willcard/decisions.jsonl`(298 条决策,效率相关 60+ 条实证)+ devflow 知识库。 +> 基调(用户原话):「从我历史使用 u-claw 的历史会话、我主张的思想中汲取知识辅助设计和决策;无人值守同时也要确保极高效率任务推进能力」。 +> 以下思想在 u-claw 侧均经生产实证,迁移 devflow 时逐条标注落点与分期。知识库已沉淀两条 workflow_optimization(f6cd9de8 派工契约/c2c0a444 A/B 层纪律)。 + +### 9.1 派工契约:颗粒约束+验收前置+首轮任务图(u-claw 09-25/09-30 拍板) + +- **废除时长预估**:不要求「预计 N 分钟」——u-claw 实证时长预估无锚定价值,超时即杀导致活任务被误杀; +- **替代契约**:①任务书必含**验收命令**(一轮内自证完成并带回验收证据) ②**超一轮未完成=派工颗粒过大**,主控拆批重派,不盲等 ③杀进程仅作卡死/跑偏兜底; +- **首轮任务图**(09-30 第 7 条):整包委托语义令下,round-0 **必须产出任务分解+派工清单**再动手,禁主控先亲手做首个任务(亲手兜底仅 1-2 行 typo 级); +- **devflow 落点**:无人值守任务书模板加「round-0 规划纪律」段(P0 文案);spawn_agent 超轮触发拆批提示(而非熔断即弃);子代理任务书 acceptance 对齐(批 2 指引真空项同源改造)。 + +### 9.2 A/B 层 prompt 纪律:预算行进 user 尾部不毁缓存(u-claw 08-31) + +- system 层(A):编排纪律五判据(耗时意识/试错预算/委派契约/超时自查/并行合并)——稳定段进 cache_control; +- **每轮 user 尾部(B):任务预算行**(当前阶段/剩余轮次/剩余 token)——user 消息注入不动 system 前缀,prompt cache 零失效(u-claw 实证口径); +- **devflow 落点**:对齐已拍板的 AC-EFF-C0-2(稳定段/易变段分离)——预算行作为易变段追加到消息流尾部,AiTaskProgress 的前端展示与后端注入同源数据;**P1 实施**(与 A9 缓存降级同批)。 + +### 9.3 换代水位 70% 主动切(u-claw 09-03) + +- rollover 判据=窗口×70%(如 1M→700K),**不等硬爆**;水位取值=最后一条 assistant 行 usage(真实窗口口径,非估算); +- **devflow 落点**:无人值守长任务压缩触发阈值联动此口径(maybe_auto_compress 判据核对,P1 顺带);devflow 主循环已有压缩链,补「长任务下水位提前」参数化。 + +### 9.4 文件互斥分区并行(u-claw 09-29-6) + +- 多代理并行按**文件清单显式隔离**,各自批次文件集无交集才能并行写; +- **devflow 落点**:spawn_agent 派工时若子代理任务书含明确目标文件集,主循环日志登记防重叠(软约束:提示词级「不要改本任务书之外的文件」已有,补主控侧登记);硬锁在 namespace owner 隔离(已设计)同批考虑。 + +### 9.5 卡片活性与聚合回填(u-claw 09-06 三连拍板) + +- 后台执行被否决:**用户以为任务丢失**;卡片须延续活性+回填结果+多任务聚合展示; +- **devflow 落点**:对齐 A12 任务面板+AiAgentFinished 完成卡(已设计);面板补「子代理状态/任务清单/等待原因/危险动作告警」四件套语义(u-claw 08-29 processing 卡四件套实证有效),P1 面板实施时并入。 + +### 9.6 失败按码分级冷却(u-claw 09-13) + +- 402/401(确定性失败)冷却 10min,其余(瞬态)30s——**确定性失败不烧重试预算**; +- **devflow 落点**:对齐已修的「Retryable/Fatal 分层」(10-02 批次2),补冷却时长分级(401/403/404 系 10min,超时/网络 30s);retry.rs 已有骨架,P2 效率批接线。 + +### 9.7 高置信自主推进决策法(u-claw 10-02) + +- 决策项先查历史指令(will-card+memory+decisions.jsonl)辅助直裁;实在不决记录挂起,**自主连续推进**; +- **devflow 落点**:已对齐——拍板集+知识库检索+挂起登记(todo 遗留),无需新增;持续把用户长期偏好(如「决策影响边界简洁呈现」「列表禁表格」)沉淀进知识库,供 AI 直裁。 + +### 9.8 汇报与决策呈现纪律(u-claw 09-28) + +- 决策须给**足够且简洁易读的影响边界**(降低决策心智投入);默认列表禁表格(宽列截断看不见内容); +- **devflow 落点**:停靠卡/NeedAction 通知文案规范(A12 面板实施时并入:一行定性结论+决策级技术事实+影响边界,列表化呈现)。 + +### 分期并入 + +| 思想 | 分期 | +|---|---| +| 9.1 round-0 任务图+验收契约 | **P0 文案**(任务书模板,P0 收尾即生效) | +| 9.2 预算行 user 尾注入 | P1(与 A9 同批) | +| 9.3 水位 70% 联动 | P1(压缩链顺带) | +| 9.4 文件互斥登记 | P1(子代理批同做) | +| 9.5 面板四件套 | P1(A12 面板) | +| 9.6 冷却分级 | P2(效率批) | +| 9.7/9.8 | 已对齐/随 P1 文案 | diff --git a/docs/02-架构设计/专项设计/跨会话召回最小闭环-设计-2026-10-04.md b/docs/02-架构设计/专项设计/跨会话召回最小闭环-设计-2026-10-04.md new file mode 100644 index 0000000..7371a3b --- /dev/null +++ b/docs/02-架构设计/专项设计/跨会话召回最小闭环-设计-2026-10-04.md @@ -0,0 +1,90 @@ +# 跨会话召回最小闭环 · 设计(2026-10-04) + +> ✅ 拍板通过(2026-10-04,3/3 按建议:B1 mention 唯一才启用/B2 软排序/B3 新增 scoped 方法;见 [拍板集](../滚动规范/拍板集-2026-10-04.md)) + +> 来源:todo.md「P1 跨会话召回最小闭环(项目级记忆+会话结束提炼进知识库,source_project 已有字段未用)」。 +> 勘察结论(2026-10-04 现场核实,以源码为准): +> - 会话内自动提炼链已存在:`knowledge_inject.rs` `extract_knowledge_from_conversation`(user/assistant 过滤+`KNOWLEDGE_EXTRACT_WINDOW` 窗口+JSON 提炼+candidate 批量插入)+ `EXTRACT_WATERMARKS` 水位防重 + `conv(cid).knowledge_extracted` 哨兵 + `trigger_extraction_now` 手动强制。 +> - `source_project` 字段在**主仓存储层零使用**:仅 `idea_repo.rs` 列定义/INSERT/UPDATE 贯通,`idea_repo.rs:949` 注释自证「source_project/source_ref 等元字段未被使用却仍随每行读出」。检索侧 `search_keywords`(idea_repo.rs:699)无项目过滤。 +> - 注入点:`knowledge_inject.rs:622 inject_knowledge_into_prompt`(`search_keywords(keywords, include_candidates, limit)`,无项目维度)。 +> - 会话→项目关联:`ai_conversations` 表**无 project_id 列**(V4 仅补 archived、V33 pending_approvals、V44 origin、V45 boundary_json);项目归属当前只能靠会话内 mention/`boundary_json`/`@项目` enrichment 间接推断。 +> - candidate→published 机制已通(自动晋升 + knowledge_promote 工具 + V43 存量迁移 854 条),**跨会话可见性**只欠「published 参与检索注入」+「项目维度过滤」两环。 + +## 1. 目标与非目标 + +**目标(最小闭环)**: +1. 会话结束(AiCompleted 收敛点)自动触发提炼时,把当前会话**归属项目**写入产出知识的 `source_project`; +2. 知识注入(`inject_knowledge_into_prompt`)按**当前项目优先**:同项目知识加权/前置,跨项目知识仍可召回但不淹没; +3. 形成闭环:会话 A 的踩坑 → candidate → 晋升 published → 会话 B(同项目)注入时优先命中。 + +**非目标(本期不做)**: +- 不做会话↔项目的强绑定 schema 变更(不加 `ai_conversations.project_id` 列)——归属用**弱推断**(见 §3.1),避免迁移风险; +- 不动 candidate 晋升策略(C3 已拍板项); +- 不做向量检索(embedding 现状 1033 条全 NULL,另线); +- 不做 UI 变更(Knowledge 页项目筛选留后续)。 + +## 2. 核心取舍:项目归属从哪来 + +会话本身不存 project_id。归属来源三选,按可靠性排序: + +| 来源 | 可靠性 | 实现成本 | 结论 | +|---|---|---|---| +| a. `boundary_json`(V45 无人值守边界)含项目路径 | 高(显式绑定) | 低(已落库) | ✅ 首选:有则用 | +| b. 会话消息中的 `@项目` enrichment / mention 记录 | 中(用户显式引用过) | 中(解析消息) | ✅ 次选:回退 | +| c. `ai_conversations` 加 project_id 列 | 高但侵入 schema | 高(迁移+全链) | ❌ 本期不做 | + +**设计决策 D1(建议拍板)**:归属采用 a→b 两级弱推断,都不命中则 `source_project = NULL`(全局知识,不过滤)。这样零 schema 变更,且与「无人值守长任务」边界模型(boundary 已带项目上下文)天然对齐。 + +**提炼函数签名扩展**(knowledge_inject.rs 内,不新建文件): + +``` +async fn resolve_source_project(db, conv_id) -> Option + // 1. 读 ai_conversations.boundary_json → 解析 project_path → 反查 projects 表 path 匹配 → id + // 2. 回退:读最近 N 条消息找 "[项目:xxx]" enrichment 标记 → 反查 → id + // 3. 皆无 → None +``` + +候选插入处(`extract_knowledge_from_conversation` 内 INSERT 前)把 `source_project = resolve_source_project(...)` 赋上。 + +## 3. 注入侧:项目维度过滤 + +**设计决策 D2**:注入不做硬过滤(`WHERE source_project = ?` 会把同问题跨项目通用知识挡死),改**软排序**——SQL 层 `search_keywords` 增加可选 `project_id` 参数: + +``` +ORDER BY (CASE WHEN source_project = ?1 THEN 0 ELSE 1 END), reuse_count DESC, ... +``` + +- 同项目知识排前(limit 截断时优先保留); +- `source_project IS NULL`(全局知识)视为第二档但优于异项目:`(CASE WHEN source_project = ?1 THEN 0 WHEN source_project IS NULL THEN 1 ELSE 2 END)`; +- `inject_knowledge_into_prompt` 调用前同样走 `resolve_source_project`(此时是当前活跃会话)取 project_id 传入; +- `knowledge_search` 工具(LLM 显式调用)暂不加项目参数——LLM 不知道当前 project_id,靠注入侧自动带。 + +**接口改动面**: +- `df-storage/crud/idea_repo.rs`:`search_keywords(&keywords, include_candidates, limit)` → 增参 `project_id: Option<&str>`(或新方法 `search_keywords_scoped`,保旧签名给 MCP 等外部调用方,内部转调); +- `knowledge_inject.rs` 两个调用点(:423 检索、:622 注入前置); +- `knowledge.rs` 工具(tools/knowledge.rs)不动。 + +## 4. 闭环验证与防劣化 + +| 风险 | 对策 | +|---|---| +| 提炼重复(每会话产相似 candidate 洪水) | 已有水位+哨兵;新增:插入前按 `title` 相似度(`search_keywords` 查同 title 命中即跳过或 `reuse_count+1`)——复用现有检索,零新机制 | +| 弱推断错误归属(张冠李戴) | 只在高置信(boundary 显式路径)时写 source_project;mention 回退可拍板是否启用(D1-b) | +| 注入 token 膨胀 | limit 不变,软排序只改顺序不增量 | +| 存量 967 条 candidate/907 published 无 source_project | 不回填(NULL=全局,行为正确);增量自然带项目 | + +**验收**: +1. 新会话提及某项目 → 完成后提炼的 candidate `source_project` 非空且指向该项目; +2. 同项目新会话注入时该知识(晋升后)排在异项目知识前; +3. 无项目会话(source_project=NULL)注入行为与现状逐字一致(回归门); +4. `cargo test -p df-storage -p df-ai` 全绿 + search_keywords 新旧签名编译兼容。 + +## 5. 拍板点(3 项) + +- **拍板1(D1-b)**:mention 回退推断是否启用?建议启用但仅当会话中项目 mention ≥1 次且唯一(多项目 mention 不猜,置 NULL)。 +- **拍板2(D2)**:注入软排序 vs 硬过滤?建议软排序(理由见 §3)。 +- **拍板3**:`search_keywords` 改签名(breaking,内部 crate)vs 新增 scoped 方法?建议**新方法**(df-mcp 等外部链路零影响)。 + +## 6. 工作量估算 + +约 1 天:resolve_source_project(2h)+ search_keywords_scoped + 两调用点接线(3h)+ 去重跳过(1h)+ 单测(2h)。 diff --git a/docs/02-架构设计/滚动规范/拍板集-2026-10-04.md b/docs/02-架构设计/滚动规范/拍板集-2026-10-04.md new file mode 100644 index 0000000..a209163 --- /dev/null +++ b/docs/02-架构设计/滚动规范/拍板集-2026-10-04.md @@ -0,0 +1,99 @@ +# 拍板集 · 2026-10-04(全量待拍板清单) + +> 用途:一次性过完所有散落拍板点,拍板后全量规划自主推进。每项附建议,逐项表态(「全按建议」或指定「#N 改 X」)。 +> 拍板通过后本文件转为决策记录,各设计文档同步销账。 + +## A. 无人值守长任务(13 项,来自 [无人值守长任务-设计-2026-10-04.md](./无人值守长任务-设计-2026-10-04.md) §拍板点清单+补遗) + +| # | 决策 | 选项 | 建议 | +|---|---|---|---| +| A1 | risk_ceiling 是否开放 High | A 封顶 Medium / B 开放 High 但破坏性命令仍拒 | **A** | +| A2 | 边界存储形态 | A 会话级 JSON 列 / B 独立任务表 | **A** | +| A3 | 边界外动作处置 | A 拒绝+记待办随停靠报告 / B 拒绝即停靠 / C 弹卡 | **A** | +| A4 | 进度事件频率 | A 每 5 轮 / B 每轮 / C 不做 | **A**(值实测后定) | +| A5 | 重启后自动续跑 | A 不自动,标记+一键恢复 / B 自动续跑 | **A** | +| A6 | 子代理是否放宽 | A 维持 Low-only fail-closed / B 继承父边界 | **A** | +| A7 | L3 完全信任 UI | A 不做 UI 文档说明 / B 设置页三档 | **A**(P2 再议 B) | +| A8 | 中途改边界 | A 全不可改 / B risk+目录锁死,预算可由用户中途调 | **B** | +| A9 | 缓存命中降级 | A 超阈值自动插 system 强制转向 / B 维持警告头 | **A**(阈值实测后定) | +| A10 | 模型分级默认 | A 卡内显式选 / B 子代理默认轻量+主循环继承会话模型,高级项可覆盖 / C 不做 | **B** | +| A11 | token 度量口径 | A 父/子分列+合计 / B 只算父会话 | **A** | +| A12 | 任务面板形态 | A 会话头部常驻面板 / B 仅侧栏徽标 | **A** | +| A13 | 预算中途调整 | A 双向 / B 只许收紧 | **A** | + +## B. 跨会话召回最小闭环(3 项) + +| # | 决策 | 选项 | 建议 | +|---|---|---|---| +| B1 | mention 回退推断是否启用 | A 启用(仅唯一 mention 才猜) / B 只信 boundary_json | **A** | +| B2 | 注入项目维度 | A 软排序(同项目优先不硬滤) / B 硬过滤 | **A** | +| B3 | search_keywords 改造方式 | A 改签名 / B 新增 scoped 方法保旧签名 | **B** | + +## C. namespace 淘汰治理(2 项) + +| # | 决策 | 选项 | 建议 | +|---|---|---|---| +| C1 | pin 上限保护 | A 加(pin 总量>50% 降级最旧 pin) / B 不加上限 | **A** | +| C2 | 报告外默认 pin 范围 | A 仅子代理报告 / B 加 run_command 大产出等 | **A**(本期仅报告) | + +## D. 完成卡已消化降级(2 项) + +| # | 决策 | 选项 | 建议 | +|---|---|---|---| +| D1 | 旧卡自动折叠 | A 默认开(touched 保护) / B 默认关 | **A** | +| D2 | ai_sub_agent_trace 工具时机 | A 随 namespace 批 / B 单独批 | **A** | + +## E. context_helpers 拆分(1 项) + +| # | 决策 | 选项 | 建议 | +|---|---|---|---| +| E1 | 拆分触发时机 | A 上下文管理批稳定后自动启动 / B 等用户指令 | **B** | + +## F. 观察转决策(3 项,使用数据分析深查产物) + +| # | 决策 | 选项 | 建议 | +|---|---|---|---| +| F1 | 压缩无 memoization 修法 | A 同内容哈希跳过(方案已在数据分析报告) / B 不修 | **A** | +| F2 | 标题源取 user 首条 | A 改取 user 首条 / B 维持 assistant 馶句 | **A** | +| F3 | checkpoints.token_total 语义失效 | A 修口径(真实 token 累计) / B 删字段 / C 不动 | **A** | + +## G. 子代理深查需拍板项(4 项) + +| # | 决策 | 选项 | 建议 | +|---|---|---|---| +| G1 | 熔断无收尾轮 | A 补一次无工具收尾 LLM 调用(报告完整化) / B 维持末轮独白 | **A** | +| G2 | 报告被视图压缩吞掉 | A 新近度豁免(报告 envelope 豁免折叠) / B 不豁免 | **A** | +| G3 | 被拒事实父上下文保留 | A LLM 压缩 prompt 加保留指令 / B 不加 | **A** | +| G4 | 子会话缺 maybe_auto_compress | A 补齐对齐主循环 / B 维持 128k 默认 | **A** | + +## H. aichat 交互成本第三批(1 项,涉开源边界) + +| # | 决策 | 选项 | 建议 | +|---|---|---|---| +| H1 | 图片默认上传外部域名 | A 上传(涉开源边界) / B 保持本地 base64 | **B**(保守) | + +## 拍板记录 + +**✅ 2026-10-04 全量拍板通过(按建议 29/29)**,方向性基调(用户原话):「未来我更倾向原生 ai-working,很多时候无人值守模式」—— + +- **A 组 13 项全按建议**:A8 采 B(预算可中途双向调,risk/目录锁死)——「一次性拍板约束 AI 不约束用户」;A5 维持 A(标记+一键恢复,桌面崩溃无自启守护,自动续跑无触发面;若未来做应用自启守护则复议); +- **B/C/D/E/F/G/H 组全按建议**;H1 保持本地 base64,上传方案留档不实施; +- **E1 维持等用户指令**——context_helpers 拆分不自主启动(备勘已就绪,随时可开工)。 + +### 全量推进规划(拍板后自主推进,批次依赖序) + +> 基调:无人值守主线优先(A 组实施=最高优先);子代理确定性项并行批次;设计实施批按拍板解锁。**无阻断,全量开工**。 + +| 批 | 内容 | 规模 | 依赖 | +|---|---|---|---| +| **1 无人值守 P0** | ✅执行侧已实现(99a3846:V45+边界放行拒绝+安全停靠+进度事件);**剩 P0 文案项:任务书模板加 round-0 规划纪律+验收契约(效率补遗二 9.1,u-claw 思想迁移)**+度量口径落库(7.3 P0 部分) | 0.5-1 天 | 无 | +| **2 子代理确定性** | 指引真空(共享指引段)+ 分离窗死点击 + 幽灵态 + 960s 统一出口 + G1 熔断收尾轮 + G2 报告豁免折叠 + G3 压缩保留指令 + G4 auto-compress + P2 确定性 4 项(max_tokens 信号/任务书钉扎/预算告知/Fatal payload) | 2-3 天 | 无(与批 1 可并行,文件域不交集) | +| **3 设计实施 I** | C 组 namespace 治理(pin+EvictionLog+owner 隔离)+ D 组完成卡降级(D2 同批:ai_sub_agent_trace+digested+KV) | 1.5-2 天 | 无 | +| **4 设计实施 II** | B 组跨会话召回(source_project 赋值+scoped 软排序+去重) | 1 天 | 批 3 后同域顺手(knowledge 域独立,实际无硬依赖) | +| **5 无人值守 P1** | 自愈+通知细化 + 任务面板(头部常驻,A12+补遗二 9.5 四件套/9.8 文案规范)+ 子代理树 + 预算窄 IPC(A13)+ 接管转人工 + 缓存自动降级(A9)+ 子代理默认轻量模型(A10)+ **效率补遗二:9.2 预算行 user 尾注入/9.3 水位 70% 联动/9.4 文件互斥登记** | 3-4 天 | 批 1 | +| **6 数据分析批** | F1 压缩 memoization(1.2 亿 token 大头)+ F2 标题源 + F3 token 口径 + P2×7(status 建模/审计耗时/blob 冗余/日志轮转等) | 2-3 天 | 无 | +| **7 机械小批** | remote_bridge 6 处+agentic 4 处裸 emit 换 emit_ai_chat_event + i18n 死键 + forceConverge 守卫 | 0.5 天 | 无(穿插 filler) | +| **8 交互成本攒批** | 9-29 第二批 P2 16 项 + UX 第四轮 P3 余 9 项 + 子代理 P3×25 | 按域分组 | 批 2/3 后 | +| **9 无人值守 P2** | 断点续跑+信任分级 UI(A7 复议)+ 暂停/恢复组合 + u-claw 接入实施(勘察已齐,relaying.ts 65bae53 可移植) | 4-5 天 | 批 5 | + +**执行纪律**:每批独立提交+核验(cargo test --workspace + vue-tsc);批 1/2 并行开;E1 context_helpers 拆分不排期(等指令);H1 无动作。 diff --git a/docs/todo.md b/docs/todo.md index d1b5d07..7daece9 100644 --- a/docs/todo.md +++ b/docs/todo.md @@ -30,7 +30,7 @@ - [x] P0 candidate→published 断链打通 ✅已修(机制先行 7c62d8d:复用自动晋升+knowledge_promote 工具+晋升补嵌入;存量晋升迁移 V43 2026-10-02 落地:candidate+confidence=high→published,库副本实证 854 条晋升 967/53→113/907,重跑幂等 0 行,df-storage 180 测试全绿;增量 confidence 分级与 auto_publish 默认值等 C3 拍板) - [x] P0 视图裁剪补滚动摘要 ✅已修(9b89610 淘汰补偿摘要插视图首部,user 角色保缓存指纹,纯视图不落库,eviction 11 测试全绿,2026-10-02 核验) - [x] P1 LLM 知识工具注册 ✅已修(7c62d8d 注册 knowledge_search/insert/promote 三工具,tool_registry.rs:798,检索与注入同源分词) -- [ ] P1 跨会话召回最小闭环(项目级记忆+会话结束提炼进知识库,source_project 已有字段未用) +- [ ] P1 跨会话召回最小闭环 ✅设计完成(2026-10-04 [设计文档](./02-架构设计/专项设计/跨会话召回最小闭环-设计-2026-10-04.md)):勘察修正——提炼链已存在(knowledge_inject.rs 水位+哨兵+手动触发),缺口仅 source_project 赋值(boundary_json→mention 两级弱推断,零 schema 变更)+注入软排序(search_keywords_scoped 新方法);3 拍板点待过,约 1 天 - [x] P1 存量测试修复 4 个 ✅已修(df3ed55 断言同步+e7cd035 笔误修正,2026-10-02 全量 cargo test --workspace 1827 passed/0 failed 复核) - [ ] P2 DB 落库截断分 role 定阈值(user 原话均 41 字被 3072 截断无必要)/namespace 重启懒重建/兜底压缩路径 sync_after_compress 复议 @@ -39,8 +39,8 @@ > 链路:devflow → u-relay → u-claw。通路已生产验证(u-ppt 试点 2026-08-29),u-relay 零改动,唯一工作面 devflow 侧接入。 > 详情:[02-架构设计/专项设计/devflow集成u-claw-可行性研究-2026-09-28.md](./02-架构设计/专项设计/devflow集成u-claw-可行性研究-2026-09-28.md) -- [ ] devflow/u-claw 两侧细勘察补全(接入点 trait/WS 渠道能力边界/多轮会话锚定) -- [ ] 接入实施:WS 客户端(移植 u-ppt relay.ts 或并入 df-tunnel)+ aichat u-claw 渠道 + 配置页(默认关,对齐 cfg.WS==nil 模式) +- [x] devflow/u-claw 两侧细勘察补全 ✅2026-10-04 完成([勘察补全](./02-架构设计/专项设计/uclaw两侧勘察补全-2026-10-04.md)):多轮锚定=channel 级单 chain 粘性会话(request_id 仅单指令标识,常驻 claude 各轮同 session_id,崩溃 --resume 恢复);**协议已漂移**——端点改 /ws/commander(commander/agent 角色,e8113c5),hello {kind,channel_id,token},不能照抄 9-28 文档/u-ppt relay.ts;新增核实:串行 worker+队列满丢弃、单条 15min 硬超时、进度 2s 节流、空闲链回收 7s 冷启动;接入实施批清单六步已列(含 per-conv channel_id 隔离策略) +- [ ] 接入实施:WS 客户端(参考 u-ppt relay.ts 65bae53——✅2026-10-04 已核,commander 协议现行对齐(端点/hello/握手/心跳/重连/业务帧六项一致),去 deck/SEP 专有逻辑即可移植)+ ask_uclaw 工具 + 配置页(默认关,对齐 cfg.WS==nil 模式);客户端超时 16min+2 次重试+发送前探活;per-conv channel_id 隔离(devflow-{conv_id}) ### 💡 2026-09-28 aichat 交互走查清尾(启动「日常主入口」标准,1P1+7P2+9P3) @@ -289,7 +289,7 @@ graph TD **P2 暂缓(窗口未到/收益低)** -- [ ] **REFACTOR-260619-09 [P2 暂缓]** — **context.rs(1332)等 F-15 压缩链路稳定再拆**。生产 745+测试 587。当前 context.rs 被压缩频繁改动,拆分窗口未到。— `crates/df-ai/src/context.rs` +- [ ] **REFACTOR-260619-09 [P2 暂缓]** — **✅事实完成销账(2026-10-04 勘误)**:原 context.rs(1332)已拆为 context/{mod,sanitize,manager_tests}.rs 目录模块,条目过时。**新超标对象=context_helpers.rs(1733 行)**,拆分备勘已出(2026-10-04 [设计文档](./02-架构设计/专项设计/context-helpers拆分备勘-设计-2026-10-04.md),四批迁移+压缩热点殿后+触发条件=上下文管理批稳定后等用户指令) — `crates/df-ai/src/context_helpers.rs` --- @@ -856,21 +856,21 @@ graph TD > 来源:上下文管理批收口期 rev-backend/rev-frontend/rev-crates 三路走查(历三次会话重启后续跑完成)。**全文与批次归并建议见 `docs/05-代码审查/aichat三路走查报告-2026-10-02.md`**。以下为可执行登记,开工以现场源码为准。 ### 批次2(后端高危)并入项 -- [ ] P0 压缩 conv_id 分裂【已亲核实锤】:`commands/chat.rs:1734` 起 cid 切 active——压缩后台会话时目标 conv compressing 永久卡死 + active 会话被插入他人摘要入库。修::1734 改 `cid = conversation_id.clone()`(约 4 行,首位) -- [ ] P0 V21 迁移 COUNT 幂等窗口:`df-storage/migrations.rs:481-488,570` 批次中途崩溃→剩余对话永不迁移但版本号补齐。修:按对话进度标记替代全局 COUNT -- [ ] P1 conv delete 不停 in-flight loop:`commands/conversation.rs:608-640` 无 stop_flag/epoch bump——zombie 复活+审批吊死。**与上方「conv 删除族 6 处」同域合并做** -- [ ] P1 只读结果缓存无写失效:`audit/cache.rs` 写后读回过期内容。修:per_conv 脏标记,写后整体失效 -- [ ] P1 OpenAI 流式 error 帧被 choices 必填整帧丢弃:`df-ai/openai_helpers.rs:193-203`(无声截断)+ 同批 serde 结构错误判 Retryable(`anthropic_compat.rs:629`/`openai_compat.rs:527`) -- [ ] P1 sanitize 合并连续同 role 丢多模态 parts:`df-ai/context/sanitize.rs:406-425` 带图消息图对 LLM 隐身。修:合并分支 extend parts -- [ ] P2-2 maybe_auto_compress protect_start 跨锁过期切片 panic:`context_lifecycle.rs:118` 加 `min(len)` 钳制(一行,与 F2 前移同域) -- [ ] P2-3 try_continue_agent_loop 裸 emit 绕过 emit_ai_completed_once:`agentic/helpers.rs:100/:171` 占位 tool_result 与 pending 残留 +- [x] P0 压缩 conv_id 分裂【已亲核实锤】:`commands/chat.rs:1734` 起 cid 切 active——压缩后台会话时目标 conv compressing 永久卡死 + active 会话被插入他人摘要入库。修::1734 改 `cid = conversation_id.clone()`(约 4 行,首位) ✅已修(2026-10-04 核验:压缩路径全函数用 conversation_id,零 active_conversation_id 引用,注释含修复说明) +- [x] P0 V21 迁移 COUNT 幂等窗口:`df-storage/migrations.rs:481-488,570` 批次中途崩溃→剩余对话永不迁移但版本号补齐。修:按对话进度标记替代全局 COUNT ✅已修(2026-10-04 核验:已改逐对话进度判定——批事务保证对话级原子,已落库数=JSON 消息数即跳过,重跑只补未迁对话) +- [x] P1 conv delete 不停 in-flight loop:`commands/conversation.rs:608-640` 无 stop_flag/epoch bump——zombie 复活+审批吊死。**与上方「conv 删除族 6 处」同域合并做** ✅已修(2026-10-04 核验:删除路径全链齐备——tombstone deleted_convs 先于 DB 删+stop_flag/notify/epoch bump 同锁停 in-flight loop+级联停子代理+审批 retain 清理+conv_states/per_conv/save_locks/semaphore 全量摘除+loop_was_alive 时 emit_ai_completed_once 单点补终态事件(带 epoch 守卫天然防重复)) +- [x] P1 只读结果缓存无写失效:`audit/cache.rs` 写后读回过期内容。修:per_conv 脏标记,写后整体失效 ✅已修(2026-10-04:PerConvState 新增 readonly_cache_floor 失效下界——非只读工具 completed 回填后推进到 messages.len(),find_cached_readonly_result 扫描 skip(floor) 过界即脏;4 个写执行回填点全接入(Low 并行/trust 放行/boundary 放行/ai_approve 审批后)+min(len) 钳制防索引漂移+单调 max;ai 域 608 测试全绿含 2 个新增锁定测试) +- [x] P1 OpenAI 流式 error 帧被 choices 必填整帧丢弃:`df-ai/openai_helpers.rs:193-203`(无声截断)+ 同批 serde 结构错误判 Retryable(`anthropic_compat.rs:629`/`openai_compat.rs:527`) ✅已修(2026-10-04 核验:OpenAiStreamChunk.choices 改 #[serde(default)]+error:Option 字段提取,apply_openai_sse 识别 error 帧返 error 载荷由 stream_llm 发 AiError;双协议非流式改 text 先取后 from_str 分层——读取中断(is_decode)判 Retryable,JSON 结构错判 Fatal 防确定性失败白烧重试预算) +- [x] P1 sanitize 合并连续同 role 丢多模态 parts:`df-ai/context/sanitize.rs:406-425` 带图消息图对 LLM 隐身。修:合并分支 extend parts ✅已修(2026-10-04 核验:ensure_sequence_legal 合并分支已含 `if let Some(parts) = m.parts { last.parts.get_or_insert_with(Vec::new).extend(parts) }`——纯图空 content 消息的 parts 随合并迁移,图不再隐身) +- [x] P2-2 maybe_auto_compress protect_start 跨锁过期切片 panic:`context_lifecycle.rs:118` 加 `min(len)` 钳制(一行,与 F2 前移同域) ✅已修(2026-10-04 核验:第二段锁内 `let cut = protect_start.min(msgs.len())` 钳制已在,注释明确记载跨锁窗口消息变短防御,与 compress_old_messages 内部钳制口径一致) +- [x] P2-3 try_continue_agent_loop 裸 emit 绕过 emit_ai_completed_once:`agentic/helpers.rs:100/:171` 占位 tool_result 与 pending 残留 ✅已修(2026-10-04 核验:两处非续跑分支(!should_continue 与 !still_generating)均改走正典 emit_ai_completed_once(零 token+notify=false),随出口终态化占位 tool_result+清 pending_approvals,注释记载防 __PENDING__ 占位残留) ### 批次3(前端体验)并入项 -- [ ] P1 后台审批/授权事件被 isCurrent 丢弃→会话挂死:`useAiEvents.ts:94-123` !isCurrent 分支对 ApprovalRequired/DirAuthRequired 放行(与 P2-5 审批数组 per-conv 合并同域) -- [ ] P1 switchConversation「对话不存在」兜底漏置 activeId:`useAiConversations.ts:294-309` 补一行(视图/高亮/发送目标三重错配) -- [ ] P2 看门狗 legacy/per-conv 双轨三错配:useAiSend.ts:169/:241/:512 统一迁移传 convId + `_resumeAttempts` 收尾清(债务本就要还) -- [ ] P2 _lastDeltas 双路径漏清:useAiEvents.ts:96-115/:154-161 补 clearLastDelta -- [ ] P2 removeGoal 不回写 store/不回滚:TopBar.vue:530-539 对齐 withConvOp 模式 +- [x] P1 后台审批/授权事件被 isCurrent 丢弃→会话挂死:`useAiEvents.ts:94-123` !isCurrent 分支对 ApprovalRequired/DirAuthRequired 放行(与 P2-5 审批数组 per-conv 合并同域) ✅已修(2026-10-04 核验:isGlobalApprovalEvent 白名单(AiApprovalRequired/AiDirAuthRequired)+isCurrent 守卫改双条件 `!isCurrent && !isGlobalApprovalEvent(event)`,审批挂起跨会话放行归口 per-conv 待审批集合) +- [x] P1 switchConversation「对话不存在」兜底漏置 activeId:`useAiConversations.ts:294-309` 补一行(视图/高亮/发送目标三重错配) ✅已修(2026-10-04 核验:兜底新建路径已含 `state.activeConversationId = created.id` 置位+持久化,注释记载旧 id 残留致 isCurrent 误路由;另附 P3-7 noCreateFallback 程序化跳转分支) +- [x] P2 看门狗 legacy/per-conv 双轨三错配:useAiSend.ts:169/:241/:512 统一迁移传 convId + `_resumeAttempts` 收尾清(债务本就要还) ✅已修(2026-10-04 核验:regenerate(:183)/editMessage(:259)/stopChat(:512+)三处均已传 per-conv convId 重置/清理看门狗,stopChat 收尾 clearResumeAttempts(activeConversationId),注释明确记载「不再落 legacy 单 timer fallback」) +- [x] P2 _lastDeltas 双路径漏清:useAiEvents.ts:96-115/:154-161 补 clearLastDelta ✅已修(2026-10-04 核验:后台终止分支(:217)与停靠卡归集分支(:131)均补 clearLastDelta,前台收尾 cleanupTerminatedConversation 亦有显式清理,注释记载防残留记录误丢下轮同内容 delta) +- [x] P2 removeGoal 不回写 store/不回滚:TopBar.vue:530-539 对齐 withConvOp 模式 ✅已修(2026-10-04 核验:removeGoal 已回写 `conv.pinned_goals = next`(注释 UX 走查-对话域 B4),防 loadGoals 重读旧列表复活已删目标) - [ ] P2 forceConverge 收敛/错误气泡缺 activeId 守卫(useAiStream.ts:115-121,与本批 onStreamTimeout 修复同家族) ### 机械批(可独立小批) @@ -878,8 +878,54 @@ graph TD - [ ] i18n searchFilesBlocked 死键裸 @(zh-CN/en aiChat.ts:198/197)转义或删 ### 登记观察(定级前先核) -- [ ] model_fetch 空列表 Ok([]) 上层写回清空模型池(df-ai 侧已核验,src-tauri provider.rs 写回点待核后定级) -- [ ] save_conversation 需核 needs_full_rewrite 检查(advance_persisted_count 无条件清 dirty);secret.rs 未走查(权限拒绝) +- [x] model_fetch 空列表 Ok([]) 上层写回清空模型池 ✅已修(2026-10-03 N1):provider.rs 空守卫跳过写回+前端 toastFetchEmpty 同语义守卫 +- [x] save_conversation needs_full_rewrite 复核 ✅已核+已修(2026-10-03 N1):实锤增量/无变化路径写库期间新置 dirty(压缩 mark)被 advance 无条件误清→改动滞留内存;改 advance_persisted_count(new,full_rewrite_applied) 仅全量清+新测试锁死;secret.rs 仍未走查 +- [x] authz_debug 残留 ✅已清(2026-10-03 N1):全仓 grep 零残留(chat.rs/state.rs 注释提及已删) + +# 子代理调度走查(2026-10-03 两路,详情 temp/走查-子代理{UX,调度后端}-2026-10-03.md) + +> 前端 13 项(P1×2/P2×4/P3×7) + 后端 P1×1/P2×3/P3×8;后端报告含 6 点「确认无恙」防重查。 + +- [ ] P1 分离窗下 TaskDrawer 关联会话死点击:openConversation detached 分支无跨窗信号不聚焦(useAiConversations.ts:661) +- [ ] P1 子代理运行期切回父会话 spawn 卡「已完成」幽灵态:回载 parseConvMessages 恒标 completed+运行期零事件(useAiConversations.ts:230) +- [ ] P1 后端 外层 960s 超时 drop 子循环 future→统一出口全跳过(报告蒸发+注册表泄漏+子会话滞留):deadline 检查下沉 stream chunk 循环或 select 超时分支特殊化补 AiAgentFinished(truncated)(audit/mod.rs:306) +- [ ] P2 rejected_tools 前端丢弃不可扫描:完成卡收字段+warn 色 chip(useAiEvents.ts:70) +- [ ] P2 完成卡纯内存重启蒸发:切换/挂载按 origin='sub_agent' 回补(aiShared.ts:630) +- [ ] P2 完成卡恒贴底时序漂移:按完成轮次桶插入(MessageList.vue:1080) +- [ ] P2 轨迹浮层无身份标识:头补 res.title/任务书首行(MessageList.vue:1584) +- [ ] P2 后端 白名单执行期不拦 Low 工具:allowed 随子循环传入 process_tool_calls(audit/mod.rs:814) +- [ ] P2 后端 父删除级联孤儿轨迹照落库:cascade_stop_children_locked 删除形态补 deleted_convs.insert(sub_agent.rs:194) +- [ ] P2 后端 S4 反查 LIMIT 1000 先截断后过滤:匹配条件下沉 SQL 或辅助索引(audit/record.rs:315) +- [ ] P3×15(前端7+后端8):deny envelope 人话渲染/浮层 Esc/spawn_agent 本地化/卡 loading/停止标「已取消」/后台完成通知/已删会话静默新建 + 并发配额挤兑/事件广播噪音/流后取消补 envelope/bypass 连带解除黑名单/落库元数据错位/peek 校验/空收敛降级/AiAgentStarted——见两报告 P3 节 + +# 子代理深查两路(2026-10-03 晚,详情 temp/深查-子代理{AI效果面,x上下文管理交叉面}-2026-10-03.md) + +> 与上节 25 项零重叠(报告尾附排除对账)。修复批:四路走查修复收口后,确定性项先行,需拍板项进拍板集。 + +- [ ] P1[确定性] 子代理指引真空:父会话实测蒸馏的四段工具纪律(read_symbol 优先/URL 三工具纪律/重复调用检测/get_app_config)未注入子代理 system prompt,而白名单缺省下发 25+ Low 工具,主会话已根治的翻车模式(一次死磕烧 1/3 预算)会在子代理原样复发;修法=抽共享指引段同源拼接 +- [ ] P1[需拍板] 熔断无收尾轮:max_rounds 打满是常态,截断时父拿到「末轮思考独白」而非报告;修法=熔断触发补一次无工具收尾 LLM 调用(涉预算策略) +- [ ] P1[需拍板] 报告被视图压缩吞掉:summarize_tool_results 无新近度豁免,报告 envelope>2KB 下一轮即被 JSON 分支折叠(512 字符),父 LLM 从未见过报告全文而 DB/前端卡是全文,追问细节答不上;涉上下文策略(stall_detector.rs:278-350/context_helpers.rs:461-513) +- [ ] P2 max_tokens=8192 截断零信号:finish_reason=length 被通道层按正常完成吞,报告腰斩仍标 completed[确定性可修] +- [ ] P2 任务书=首条 user 消息,超预算时第一个被逐出且子代理无目标钉扎(主循环有,子循环显式传空 sub_agent.rs:594)[确定性可修] +- [ ] P2 预算三值(轮次/token/900s)不告知子代理,系统提示词硬编码「默认最多 6 轮」[确定性可修,文案] +- [ ] P2 Fatal 错误细节被吞(RoundOutcome::Fatal 无 payload),父拿无因报告无法针对性重派[中小扩参] +- [ ] P2 namespace 10MB 全局 LRU 淘汰:报告蒸发为「重新调用」死路+多代理共池互踩 ✅设计完成(2026-10-04 [设计文档](./02-架构设计/专项设计/namespace淘汰治理-设计-2026-10-04.md)):pin 机制+EvictionLog 富提示(替代裸 EVICTED_PLACEHOLDER)+owner 软隔离三招,零 schema 变更;2 拍板点(pin 上限保护/报告外默认 pin 范围),约 0.5-1 天 +- [ ] P2 被拒事实父上下文仅报告尾段单副本,LLM 压缩 prompt 无保留指令[需拍板] +- [ ] P2 完成卡(前端全文)与父上下文(压缩)双轨无「已消化」降级机制 ✅设计完成(2026-10-04 [设计文档](./02-架构设计/专项设计/子代理完成卡已消化降级-设计-2026-10-04.md)):勘察修正——重启回补已存在(aiShared.ts:677 ai_sub_agent_list 反查重建),设计聚焦 digested 标记(KV 持久)+卡降级交互+ai_sub_agent_trace 只读工具(LLM 追问自助通道,兼为 namespace 蒸发兜底);2 拍板点,约 1-1.5 天 +- [ ] P2 子会话缺 maybe_auto_compress 层+预算恒 128k 默认[需拍板] +- [ ] P3 spawn task 全文永续无瘦身/8KB 截断文案对子代理语境失真/环境画像日期不注入/报告 8K 头尾截断恰切证据区/temperature 0.7 共享/model 回退不回报/namespace 挤兑/一次性语义未向父声明/报告约定缺「文件路径原样保留」/语言无 lang 参数——见两报告 P3 节 +- [ ] 观察 uf2 修复引入:取消判定 summary.includes('已被取消') 中文子串启发式,根治=后端透出结构化 stop_reason/取消标志字段 + +# 无人值守长任务(2026-10-04 用户拍板方向,设计先行) + +> 用户拍板:审批类(S2-B 真审批通道)延后不做;产品主线=任务规划一次性确定边界后,无人值守、自主无干预、稳定完成长任务,用户体验优先零打断。追加两维度:效率(完成快+tokens 高效)、可观测可控(进度花费看得见,暂停纠偏接管控得住)。 +> 设计文档已定稿:docs/02-架构设计/专项设计/无人值守长任务-设计-2026-10-04.md(257 行,含效率/可观测可控补遗两章),拍板点 13 项各带建议。 +> 缺陷靶心分析:temp/深查-无人值守稳定性缺陷-2026-10-04.md(P1×5/P2×7+效率 5+观测可控 5,接驳点已标注)。 + +- [ ] 设计评审后按分期实施(P0 边界模型+旁路主干 → P1 自愈+通知 → P2 断点续跑+信任分级) +- [ ] P1 缺陷随分期消化:~~①审批超时取消后循环永不恢复~~ ✅①已修(2026-10-04 核验:cancel_expired_approval 第6步清幽灵态迁回 Idle+第7步安全停靠 AiTaskParked+NeedAction 通知,audit/mod.rs:530-555) ②spawn_agent 注册 Medium 无人值守动线停摆(归 P0 旁路) ③MidStream 断流=整任务终止(入打断点表,P1) ④轮级重试 30s 总预算全候选共享无跨轮重入(P1,任务级重入;工作区已见 ROUND_REENTRY_MAX 跨轮重入层在飞实施,待合入核验) ⑤重启后任务静默失踪(归 P2 断点续跑) +- [ ] P2 缺陷登记:panic 收尾伪装正常完成无通知/context_length Fatal 无降级/空回复静默假成功/前端 3 次探测强制收敛与后端分裂/checkpoint 审计只增不清 +- [ ] 效率面:模型无轮内分级/警示消息打断前缀缓存/换参同语义死磕不计数/子代理串行 await/token 花费中途不可查/纠偏只能排队不能注入/预算中途调整不可达(归设计补遗两章分期) # 后续规划方向(2026-10-02 用户口述,不分先后) @@ -894,3 +940,66 @@ graph TD 7. UX 体验交互体验(批次3 及后续 UX 批持续线) 8. 内置数据库、远程服务器连接能力(与代理工具生态 mysql-proxy/ssh-proxy 等整合) 9. 远程内网设备文件程序管控(中继+代理 client,内置于 u-desk/devflow 或全新设计,关联 u-relay) + +# 使用数据分析深查(2026-10-04,logs+DB 实证,详情 temp/使用数据分析-1004/) + +> 89 会话/15126 消息/9398 工具执行(3.5 个月真实使用);全文与 out1~out7 中间数据见分析目录。修复以现场源码为准。 + +- [x] P0 git.rs:161 字节切片撞 UTF-8 边界 panic(中文 diff 必炸,13:44 两次实证) ✅已修(分析当场,回退字符边界) +- [x] P1 Temperature 原样透传不支持的模型(sensenova 等仅允许 1,9 次 400 实证)——按模型适配/省略 ✅已修(2026-10-04:ModelConfig 加 temperature_supported 字段+presets 标 sensenova-6.7-flash-lite=false+启发式 sensenova 前缀判定;openai/anthropic 双协议转换层不支持即省略字段;df-ai 560+df-ai-core 33 测试全绿含新增锁行为测试) +- [ ] P1 压缩无 memoization:view-only 压缩 2280 次中 369 组同内容反复压(最坏 54 次),prompt 1.2 亿 tokens=completion 115 倍——同内容哈希跳过 +- [ ] P1 标题采到 assistant 首句('信息已足够。让我看一眼...'/'
P1 零;P2×7/P3×11;已修三轮清单已硬排除。修复批开工以现场源码为准。 + +- [x] P2-A2 边界配置卡目录白名单零校验 ✅已修(词法校验+就近红字),坏路径拖到运行期才暴露(TaskBoundaryCard.vue:163) +- [x] P2-A1 边界拉取失败静默降级 ✅已修(failed 态+授权禁用+重试)默认表单,一次授权即静默覆盖原授权(TaskBoundaryCard.vue:126+useTaskBoundary.ts:25) +- [x] P2-A4 熔断时求助卡被停靠卡顶替 ✅已修(AiTaskParked 保留 pendingHelp),help options 决策项丢失(useAiLifecycleEvents.ts:87,239) +- [x] P2-A3 generating 锁编辑连带锁死 ✅已修(清除解锁+confirm)「清除边界」(收权被盖,纯前端限制)(TaskBoundaryCard.vue:77,232) +- [x] P2-B1 非视觉模型贴图发送前零感知 ✅已修(modalities 判定+警示 chip),静默丢图(ChatInput.vue:185,modalities 全链路未消费;数据实证三连手敲重试) +- [x] P2-B2 纯发图+非视觉模型 ✅已修(前后端双闸拒纯图),占位串当用户消息喂模型跑偏一轮(chat.rs:789) +- [x] P2-B3 error_type 大面积 Unknown ✅已修(classify_permanent→ProviderConfig CTA),永久错误也显「重试」必再败(MessageList.vue:688+mod.rs:596) +- [x] 回归疑点 App.vue:227 全局快捷键 ✅已修(双文件 target 守卫+AIChat:339)(Ctrl+I/N/R/L/K/B)无 target 守卫,仅 Esc 有(走查复核提请,修时验证) +- [ ] P3×11(文案四条已顺带修 ✅:fatal 矛盾措辞/cancelled 续跑 CTA/high 裸串/TopBar ellipsis;余 9 布局+虚拟滚动+压缩面包屑待批) + +# 后续规划登记(2026-10-04 用户口述) + +- 各模块 UX 走查(全模块逐域走查,ai-chat 已做完四轮,剩余:项目/任务/工作流/想法池/知识/设置等域)——待令启动,建议逐域分批 + +# DevFlow agent 狗粮实测短板(2026-10-04,84cb104c 会话数据实证,登记待排批) + +> 当日 ~810 次工具调用;主循环配置 max_iterations=0(不限)实证 225 轮零触顶;子代理 spawn max_rounds 6 默认/模型自给 10→20(上限 20)。 + +- [ ] P1 工具纪律失守:read_file 本支持 offset/limit 分页+search(工具描述明示)但模型不用,67+ 次 run_command PowerShell/python 切片绕道读文件——大文件 read_file 自动截断返回并带「用 offset/limit」引导+系统提示词禁 run_command 读文件 +- [ ] P1 patch_file old_text 未命中 28%(38/136,全部「未找到目标文本」):加空白归一化回退匹配(唯一命中自动采用并提示),工具描述教「3-5 行锚点小步 patch」 +- [ ] P2 子代理默认 max_rounds=6 偏小,父试探性提到 10/20:默认提到 12 或按任务书长度给建议值 +- [ ] P2 验证烧轮:全量 cargo check 多次(单次数十秒),引导 check -p 单包/单文件快检策略 +- [ ] P3 并行子代理轮次徽标无身份,交错显示「第3轮/第2轮」致乱序观感(机制=各自独立计轮,正常):徽标带 agent 序号/任务首词 + +# 新能力引入评估纪律(2026-10-04 用户令,长期生效) + +> 引入任何新能力(协议/工具/机制/大重构)前,须做负面影响与破坏性判定,登记在设计文档内;审查(Review 会话)按此清单核。四维度基准:功能/接口适配/内容风格/性能,禁「未发现故障=不受影响」。 + +- [ ] **兼容性**:旧数据/旧客户端/旧配置共存与迁移路径;迁移须可断点续跑(借鉴 V21 教训)且可逆(SQL 迁移带 DOWN 或等价回退) +- [ ] **破坏性**:不可逆操作清单(删数据/拆兼容层/改协议旧值拒认);每项须有回退方案或「为何不可回退」论证 +- [ ] **安全面**:新增攻击面(端点/帧/命令执行/路径)逐项列;权限是否放大(对齐边界模型 risk 分级) +- [ ] **资源面**:token/磁盘/内存/进程开销评估;日志与数据膨胀上限(借鉴日志无轮转教训) +- [ ] **回退开关**:新能力默认关或带单点回退(借鉴 GOAL_PIN 系开关范式);灰度顺序与观测指标 +- [x] **追溯评估(实例,2026-10-04 完成)**:u-relay wire v3(「兼容层全拆」)——初判「零评估章」系 grep 截断误判,实有 §8 安全说明+§9 旧版差异;正式评估结论:生态四方(relay 现网/u-ppt/df-miniapp/df-tunnel)已全部 v3 一致,切换期破坏已吸收(均为开发期集成,无生产 SLA 损伤)。残余缺口登记: + - [ ] P2 指令离线即丢(§7 不缓存):commander 发指令时 agent 离线=静默丢失,移动端控制场景用户无感知——补业务层送达回执或短缓冲 + - [ ] P2 Hello 无协议版本字段:下次破坏性变更仍是无通知硬切换——加 proto 版本字段(现在加便宜,以后加贵) + - [ ] P3 单共享 token 可冒充任意 channel_id(§8 自述):补 token 轮换 runbook(/etc/u-relay.env 改+重启+四方客户端同步换,锁步成本需写明) + - [ ] P3 心跳间隔未定值:nginx proxy_read_timeout=300s,间隔须 <300s,文档补建议值(30-60s) + - [ ] P3 同 channel_id 多 agent 并存全投递(§3.3):双 devflow 实例共享通道=指令重复执行,补「一通道一 agent」运维纪律