# dsh-escrow v0.2.2 设计细则(范围裁剪版) > 状态:v0.2.2 修订稿(在 v0.2.1 基础上做范围裁决:全部 8+1 模块 → 核心 M1+M2+M7 + M8-lite + M6-lite) > 修订要点速览: > - **在范围**:M1 非阻塞托管(轮询式)、M2 品味习得、M7 自改治理、M8-lite(重复动作 + SNR-lite + 署名)、M6-lite(session/turn 字段 + 账本哈希链 + 最小报告) > - **折叠**:M3 批量审阅 → 并入 M2 命令(`approve all` / `deny all`) > - **推迟到 v0.3**:M4 补偿引擎本体(v0.2.2 只保留分类期"可补偿性标记"支撑宪法第 4 条)、M5 通知/审批分离、M9 doctor 全量、M8 的零变更写入检测(依赖 M4 objects) > - **新增 W0 闸门**:真实 dsh 端到端验证 v0.1.1 + S0 三 spike;spike 失败则 M1 降级 sync 增强版,其余模块不受影响 > - 裁决依据:独占位分析(生效前托管 + 品味习得 + 署名)。M1+M2+M7 只覆盖前两位;署名位的最小可用件(重复检测/SNR/署名尾注)是 M2 签名基础设施的副产品,成本仅数天。M4/M5 非独占且最贵最易延期。 --- ## 0. 设计目标与原则 | 问题 | v0.1.1 现状 | v0.2.2 目标 | |---|---|---| | agent 会停顿 | 红灯动作同步等待 | **非阻塞**:入队即返回"已托管",模型可轮询结果 | | 打扰用户 | 每个红灯都要确认 | **品味习得**:签名级白名单 + 冷却期 + ROI 可见 | | 注意力缺席时裸奔 | 只有拦截没有兜底 | **损失有界**:可补偿性标记 + 自改治理(补偿引擎本体 v0.3) | | 减法缺位 | 只拦危险不管冗余 | **编辑者职责**:重复审计 + 信噪比 + 署名 | **宪法条款(Constitution,不可通过配置关闭的硬规则,写在代码常量中,测试覆盖防回归):** 1. **审批通道永不暴露为模型可见工具**——`/escrow approve` 只走 human command 通道,handler 校验人类 UI 事件源(防"模型自我批准") 2. **`.dsh-escrow/` 自身目录写入恒为 red**——账本/白名单/黑名单/密钥是防线本体(防自我篡改) 3. **自改类签名永不进入品味习得**——只能手动、显式加入(防孔某人失败模式复刻) 4. **不可补偿动作的超时恒为 cancel**——`release` 对其无效(不能救的就更该拦;v0.2.2 以分类期"可补偿性标记"判定,见 M4 推迟说明) 5. **fail-closed 恒开**——超时/异常/令牌过期一律拒绝,silence means no **其余原则**:确定性规则优先(绝不用 AI 分类器做安全决策);账本是唯一事实源;注意力是预算(同一签名只打扰一次);**范围即安全面——每个模块都在放大审计面,砍掉的模块不是损失是减负。** --- ## 1. 功能模块总览(v0.2.2 范围裁决) | 模块 | 状态 | 说明 | |---|---|---| | M1 非阻塞托管 | ✅ 在范围 | W0 spike 通过才动工 | | M2 品味习得 | ✅ 在范围 | 纯函数先行;sync/async 两种模式下均成立 | | M7 自改治理 | ✅ 在范围 | 内置规则 + 不可学习名单 + 强制快照标记 | | M8-lite 减法审计与署名 | ✅ 在范围(收缩) | 只做:重复动作 + SNR-lite + 署名;零变更检测随 M4 推迟 | | M6-lite 账本治理 | ✅ 在范围(收缩) | session/turn 字段 + 哈希链 + 最小报告(署名载体) | | M3 批量审阅 | 🔀 折叠进 M2 | 只保留 `approve all` / `deny all` 两条命令 | | M4 命令层补偿 | ⏸️ v0.3 | 保留分类期可补偿性标记;快照/undo 引擎推迟 | | M5 通知/审批分离 | ⏸️ v0.3 | 非独占位(Vultrino 已做外部通知);无头由 `ttlSec: 0` 兜底 | | M9 doctor 全量 | ⏸️ v0.3 | 只保留账本哈希链(随 M6-lite 落地,避免日后改格式破坏兼容) | **范围稳健性说明**:M2 / M7 / M8-lite / M6-lite 在 sync 模式下同样成立。即使 W0 spike 判定非阻塞此路不通,仍交付品味习得 + 署名 + 自改治理——两个半独占位不受 M1 风险连带。 --- ### M1 非阻塞托管(轮询式,重写) **v0.1.1 现状**:`pre-execute` 同步等待(agent 暂停 30 秒)。 **修订说明**:deferContext 跨轮注入方案**已被否决**——deferContext 绑定单次执行生命周期,合成结果即 final result,批准时窗口已关闭(评审 P1)。 **轮询式设计**: - 分类仍在 `tools/pre-execute`;拦截与合成结果在 `tools/execute`(around-dispatch) - **红灯流程**: 1. 入队(记 `escrow.queued`) 2. `tools/execute` 包装器**不调 next()**,返回合成结果(**定案形态:Success / foreground 合法前台结果**,2026-08-29 S0 spike 实证通过): - 结构:`{ kind:'foreground', exitCode:null, signal:null, timedOut:false, aborted:false, timeoutMs:0, stdout:{text,truncated:false}, stderr:{text:'',truncated:false} }` ——完全符合目标工具(bash/pwsh)的 output 声明,`additionalProperties:false` 下无多余字段,wrapper 规范化安全。 - 占位文本(自带行为指令):`「动作 esc-xxx 已进入托管队列,尚未执行。需要结果时调用 escrow_result(esc-xxx) 查询;审批期间不要重复发起同一命令;不依赖此结果的工作可继续。」` - 选 **Success** 而非 Failure:Failure 以 `Error:` 前缀呈现给模型,易诱发"失败→换法重试"直觉;实证中模型收到 Success 占位后不重试、主动轮询 `escrow_result`。 3. 批准(human command)→ 生成**一次性重放豁免令牌 = 随机 callId**(P2 落实:模型无法铸造 callId——模型直调时 callId 由 registry 分配,Code Mode 子分发是确定性 `:code:`;批准时铸随机 callId,存 `hash(工具名+规范化参数) → callId`)→ 重放执行(携带令牌 callId,pre-execute 验证后豁免**一次即删**)→ 记 `escrow.approved_executed`。令牌**绝不进 arguments**(pre-execute 不能改写 args,且 args 进日志、模型可见)。重放时透传原 `exec.agent` 保证会话归属。 4. 拒绝/超时 → 记 `escrow.denied_executed` - **同签名 pending 去重**:模型等待期间重复发起同一签名(规范化后)调用时,**不再入新队列**,直接返回既有条目 id 的合成结果(`「此命令已在审批队列 esc-xxx,请用 escrow_result 查询」`)。防重复入队刷队列;与占位文本"不要重复发起"互为双保险。 - **新增模型可见只读工具 `escrow_result(id)`**:返回托管动作状态(pending / executed+真实结果 / denied+理由)。模型按需查询,不查询也不阻塞。 - **syncTools 逃生门(P9)**:`syncTools: []` 允许把"后续强依赖结果"的工具(典型:写后读)留在同步模式。 - **误依赖观测(N5)**:合成结果嵌入一次性标记;后续动作引用相关路径则计数"误依赖",进报告(非阻塞设计的健康指标)。 - **降级**:`mode: async | sync`,async 链路异常自动降级 sync(v0.1.1 行为),README 明示。 - 通知触发点保留(入队时调 M5 接口位),M5 推迟期间为空操作。 **S0 实证记录(2026-08-29,证据等级:实证级)**:真实 headless agent(escrowtest profile + dsh-synth-probe)收到合成结果后,**未重复发起同一命令**(echo 命令全程仅 1 次),主动多次轮询 `escrow_result`(7 次)获取 pending 状态,最终如实汇报"等待审批";`escrow_result` 作为模型可见工具注册实机可用、模型正确理解 pending 语义。附带观察:模型尝试 `Start-Sleep` 等待审批(同样被托管为 esc-xxx),属无害等待行为,不影响安全。 **S0 Spike 清单(3 项,W0 闸门的一部分)**: 1. `tools/execute` 返回合成结果后,agent loop 是否重试风暴 2. `escrow_result` 的模型可见注册姿势(含 Code Mode 投影) 3. 重放令牌在 pre-execute 的验证路径 **W0 决策规则**:spike 1 出现重试风暴且无法通过合成结果文案/系统提示引导 ⇒ 放弃 async;`escrow_result` 无法注册为模型可见工具 ⇒ 轮询式整体不成立,M1 转 sync 增强版(保持 v0.1.1 行为 + 批量命令 + 摘要优化)。 ### M2 品味习得(含 M3 折叠命令) - **稳定签名提取(白名单式规范化,P7)**:只有匹配已知安全形态(分支名、数字、哈希)的 token 替换为通配符;`--` 开头的 flag 一律保留原文。例:`git push origin ` 合法,`git push origin --force` 中 `--force` 保留原文(即不与普通 push 同签名)。 - **审批卡结构化字段**:托管条目保存动作、目标对象、远端、分支/引用、URL、数据库/架构、资源和权限范围等低敏字段;同时传递 riskClass、审批 choices、阈值和冷却策略。 - **学习规则**:批准达到 learnThreshold(默认 2)次后,默认冷却期(默认 24 小时)结束才自动放行;审批卡可选择达到阈值后立即放行。拒绝达到阈值后,相同签名直接拒绝且不再请求人工审批。 - **不可学习名单(never-learn,P7)**:`rm -rf` 类、任何带 `--force`/`-f` 的破坏性命令、磁盘类(`dd`/`mkfs`)、**自改类(M7)**——无论批准多少次都不自动放行,只能手动 `/escrow allow`(带确认提示)。 - **失效机制**:插件树 hash 变化 → MCP/工具类条目标记"待复核"。 - **品味包(Rubin 叙事)**:`/escrow export|import` —— 白名单+黑名单+规则导出为带版本号与 SHA-256 校验和的 `escrow-taste-pack.yaml`,团队可共享、可签名、可审计。导入时校验和不符拒绝加载。导入后条目进"待复核"状态。 - **命令**:`/escrow allowlist | allow | deny | forget | export | import | approve all | deny all`(后两条为 M3 折叠——批量只批"同签名"组,不提供无差别全批)。 ### 外部副作用与权限分类(v0.3.23) - shell 高置信度规则将包/容器发布、HTTP POST/PUT/PATCH/DELETE、集群/基础设施变更、系统服务/计划任务/注册表、权限提升和数据库写入纳入 red;只读的 `plan/get/test/status/diff/commit` 不因命令名称自动变红。 - 非 shell 工具不按名称猜测副作用。宿主或管理员可通过 `trustedToolEffects` 声明 `external-write`、`privileged`、`destructive`、`shared-resource-write`、`secret-read`、`governance`;可信标签在用户规则和品味白名单之前裁决,并沿托管队列传递到 never-learn。 - 工具参数里的自报字段、未经验证的 MCP annotations 不作为安全裁决依据。MCP schema 将 annotations 定义为提示而非保证,因此仍需宿主侧可信注册。 - 高影响动作进入 red;force push、生产/共享资源删除、正式包/容器发布、权限提升、安全策略变更和 dsh 自身治理变更标记为 critical-red。critical-red 每次默认人工审批,不因批准次数达到阈值自动放行。 - 普通 git push 也进入 never-learn。never-learn/critical-red 审批卡明确说明“即使人工批准很多次,也不会自动进入白名单”;用户仍可通过 /escrow allow 或“批准并加入白名单”承担明确风险。 ### M7 自改动作治理 - 内置规则:写路径命中 `$DSH_HOME/**`、`AGENTS.md*`、profile 的 `cordis.patch.yml`/`package.json`、自身源码目录、记忆/大盘文件 → **red** - **永不进入品味习得**(P4,宪法第 3 条);批准也强制留 before 快照标记(快照本体随 M4 落地,v0.2.2 记录快照指针与 hash) - 报告单列"自改动作"统计维度;批准时尽力附 diff 摘要 - config:`selfModification.red: true`(可关,但关闭会告警) ### M8-lite 减法审计与署名(收缩版) **竞品实况(2026-08-28 调研)**:`dsh-plugin-prune` 已实现纯观察的插件体检——按工具/技能聚合调用数、错误率、延迟、跨会话使用,标记 never-used / failed / marked-useless。**冷工具/冷插件维度不做,引用 prune 或提示用户安装。** **`/escrow reduce [--since 7d]`(v0.2.2 范围)**: | 维度 | 检测逻辑 | 输出 | |---|---|---| | 重复动作 | 同一签名执行 ≥ N 次(默认 10)——**复用 M2 签名提取,零额外基础设施** | "重复 47 次,建议缓存/合并" | | SNR-lite | `SNR = (总动作 − 重复) ÷ 总动作`;辅助:重复率 / 打扰率 | 月度成绩单 | | 署名 | 见下 | 报告固定尾注 | | (可选)prune 数据 | 若检测到 prune 的 JSON 统计则整合并注明来源 | 统一成绩单 | **推迟到 v0.3**:零变更写入检测(依赖 M4 objects 的前后内容比对)。 **边界(宪法级)**:**永不自动卸载**——编辑者给建议,创作者拍板;冷工具/冷插件结论引用 prune 数据时注明来源。 **竞品关系备注**:审批自动决策层已饱和(dsh-approve-for-me / dsh-managed-approval / dsh-auto-approve / dsh-approval-llm 共 4+,社区惯例"一 profile 一个 permission-review 插件")——escrow 不注册 approval/request answerer,与其无冲突;定位保持"延迟执行给人、不自动决策"。 **署名**: - 月度报告固定结尾—— `── Reduced by dsh-escrow ── 本月:拦下 12 · 静默 3,206 · 建议减去 2 · SNR 0.41 → 0.58` - 原"成本显示"**并入本模块**(token/缓存占用随报告输出,依赖 `dsh-token-meter`/`dsh-session-telemetry`,可选) ### M6-lite 账本治理与最小报告(收缩版) - **会话上下文(P10)**:每条 ledger 记录补 `session`(从 `exec.agent` 派生)与 `turn` 字段;审计可回溯到会话/回合 - **账本哈希链(从 M9 提前,理由是格式兼容)**:每行记录带 `h = sha256(prevH + 行内容)`,启动时校验末行哈希;被截断/篡改 → 告警。这是署名叙事的可信根基:公开轨迹必须防篡改才可作为信用凭证。 - **`/escrow report [--json|--md] [--since 7d]`(最小版)**:统计(总数/分布/拦下数/批准率/平均等待)+ 红灯清单 + 品味习得记录 + 自改记录 + **注意力 ROI**(确认次数、平均耗时)+ M8 署名尾注 - 轮转沿用 v0.1.1 已实现(`ledgerMaxMb`,单代 `.bak`);50MB/90 天双条件与 `.1/.2` 多代推迟到 v0.3 - **署名**:报告固定结尾 `── Reduced by dsh-escrow ──`(见 M8-lite) ### M3 批量审阅(🔀 折叠进 M2) v0.2.1 的紧凑摘要/分组展示/断点提示推迟。v0.2.2 只保留两条队列命令(见 M2 命令清单):`approve all` / `deny all`——按同签名分组批量操作,不提供无差别全批(防"一键清空队列"绕过注意力预算原则)。理由:M2 生效后队列量下降,批量审阅是冷启动期舒适件而非承重件。 ### M4 命令层补偿(⏸️ 推迟到 v0.3,保留可补偿性标记) **推迟理由**:补偿正确性是硬问题——错误的 undo 比没有 undo 更糟;引擎本体(objects 快照、反向命令生成、`/escrow undo`)需要独立一周以上的设计与验证,且非独占位(dsh-rollback 管文件层)。 **v0.2.2 保留(宪法第 4 条需要)**:分类期**可补偿性标记**——对 red 动作确定性判定 `compensable: yes | no | unknown`(只对可完全解析的简单命令判 yes:单命令、无变量展开、无管道、字面量参数);`no`/`unknown` 且 `timeoutPolicy: release` 时强制按 cancel 处理并记账说明。 **v0.3 落地**:文件删除/写入的 objects 快照与恢复、git 反向命令、`/escrow undo`(默认 dry-run)、与 dsh-rollback 共享 objects。 ### M5 通知与审批分离(⏸️ 推迟到 v0.3) **推迟理由**:外部通知不是独占位(Vultrino 模式已有实现者);无头闭环已由 `ttlSec: 0`(v0.1.1 已修复)兜底;bot 回传轮询 + loopback HMAC 令牌服务是 3–5 天纯增量,随时可插回。M1 的入队通知触发点以空接口保留。 ### M9 运维命令(⏸️ 推迟到 v0.3,哈希链提前) `/escrow doctor` 全量自检(白/黑名单 schema、密钥文件权限、插件树 hash、规则数上限、性能指标)推迟到 v0.3;**账本哈希链提前到 M6-lite**(改变写入格式,必须现在定)。v0.2.2 保留:allowlist/denylist 加载时 schema 校验,失败拒绝加载并告警。性能预算(N4)不变:分类器热路径附加延迟 < 1ms;规则数上限 256;正则预编译缓存;超预算告警。 --- ## 2. 配置(v0.2.2 完整字段) ```yaml config: # v0.1.1 已有(ttlSec=0 已修复、轮转的 ledgerMaxMb 已落地) ttlSec: 30 timeoutPolicy: cancel # cancel | release | hold(标记不可补偿的动作强制 cancel) defaultAction: yellow builtinRules: true rules: [] ledgerDir: "" ledgerMaxMb: 32 # v0.2.2 新增(在范围) mode: async # async | sync(降级;spike 失败则默认 sync) syncTools: [] # 工具级同步逃生门 learnWhitelist: true learnThreshold: 2 autoBlacklist: true cooldownHours: 24 # 白名单冷却期 approvalChoices: immediateAllow: true manualWhitelist: true selfModification: red: true reduce: repeatThreshold: 10 snr: true # SNR-lite 指标计算 # v0.3 预留(当前无效,保留字段防配置 Breaking Change) notification: enabled: false # M5 推迟 webhookUrl: "" telegramBotToken: "" telegramChatId: "" httpPort: 8787 # 随 M5 推迟 costDisplay: false # 已并入 M8-lite 报告 ``` --- ## 3. 数据模型 ``` $DSH_HOME/.dsh-escrow/ ├── ledger.jsonl(.bak) # 唯一事实源(append-only + 哈希链自检;轮转沿用 v0.1.1) ├── allowlist.json # 品味档案 [{signature, count, lastAt, source, cooldownUntil}](加载时 schema 校验) ├── denylist.json ├── taste-pack.yaml # 导出的品味包(版本 + 校验和) ├── objects/ # ⏸️ v0.3:M4 补偿快照(sha256 寻址) └── keys/hmac.key # ⏸️ v0.3:M5 审批令牌密钥 ``` **ledger 记录格式(v0.2.2)**:每行含 `t` / `kind` / 载荷 + `session` / `turn`(P10)+ `h`(哈希链:`sha256(prevH + 行内容 sans h)`,首行 prevH 为 `"genesis"`)。 **ledger kinds(v0.2.2 在范围)**:`observe` / `escrow.queued` / `escrow.decided` / `escrow.whitelisted` / `escrow.blacklisted` / `escrow.approved_executed` / `escrow.denied_executed` / `escrow.replayed`(含令牌验证记录)/ `selfmod.queued` / `selfmod.decided`。 **⏸️ v0.3**:`escrow.notified` / `compensate.generated` / `compensate.executed`。 --- ## 4. 测试计划 | 层 | 内容 | |---|---| | 单元 | 签名提取(含 flag 保留的规范化)、不可学习名单、冷却期、可补偿性标记、重复检测、SNR-lite、哈希链(含篡改检测)、品味包校验和 | | 集成 | 轮询式全流程(合成结果 → escrow_result 查询 → 批准/拒绝)、重放令牌豁免、`approve all`/`deny all` 按签名分组、报告含署名、品味包导出导入、allowlist schema 校验失败拒载 | | W0 闸门 | 真实 dsh 端到端验证 v0.1.1(rm -rf 被托管、/escrow 全命令可用、deny 契约生效)+ S0 三 spike | | 回归 | v0.1.1 全部测试持续通过(43 单元 + 14 集成) | --- ## 5. 风险与依赖 | 风险 | 等级 | 对策 | |---|---|---| | 合成结果后 agent loop 重试风暴 | 高 | W0 spike;重试则改用 `escrow_result` 主动查询引导 + 系统提示注入;不可引导则 M1 转 sync 增强版 | | escrow_result 的 Code Mode 投影 | 中 | W0 spike 2 验证 | | 重放令牌被模型侧伪造 | 低 | 令牌只存在于本机内存/密钥文件,永不进入模型上下文 | | 品味包导入投毒 | 中 | 校验和 + schema 校验 + 导入后条目进"待复核"状态 | | 白名单签名过宽 | 中 | 白名单式规范化(P7)+ 不可学习名单 + 冷却期 | | 哈希链格式后悔 | 低 | v0.2.2 即定型,写入路径向后兼容校验(无 h 字段的旧行视为链外历史,只告警不拒绝) | | ~~M4 补偿错误造成二次损害~~ | — | 已随 M4 推迟出范围 | **依赖**:`dsh-agent-loop`(S0 验证)、`dsh-token-meter`/`dsh-session-telemetry`(成本,M8-lite,可选)、`dsh-rollback`(objects 复用,v0.3)。 --- ## 6. 里程碑(单人,3.5–4 周;原 v0.2.1 为 5–6 周) | 阶段 | 内容 | 周期 | |---|---|---| | **W0(闸门)** | 真实 dsh 端到端验证 v0.1.1 + S0 spike 三项 | 3–4 天 | | W1–W2.5 | M1 轮询式(spike 通过才动工)∥ M2 品味习得(纯函数先行,含折叠的 M3 命令) | 2.5 周 | | W3 | M7 自改治理 + M8-lite(重复/SNR-lite/署名)+ M6-lite(session/turn、哈希链、最小报告) | 1 周 | | W3.5–W4 | 加固、文档、发布 | 3–4 天 | **W0 失败分支**:spike 不通过 → M1 转 sync 增强版,W1–W2.5 缩短约 1 周,总周期约 2.5–3 周,其余模块与验收不变。 --- ## 7. 明确不做 **v0.3**:M4 补偿引擎本体(objects 快照 / 反向命令 / undo)| M5 通知/审批分离(webhook、Telegram bot 回传、loopback HMAC 服务)| M9 doctor 全量 | M8 零变更写入检测 | 完整输出依赖追踪(真 SNR)与跨层事务 | 插件来源守卫 | 取证级轨迹导出 | Web UI 审阅页 | 账本轮转 50MB/90 天双条件与多代保留 **v1.0**:与 dsh-permission-rules ask 档对接 | 公网审批网关 | 品味订阅市场(taste pack 分发) --- ## 8. 验收标准(可证伪,v0.2.2) 0. **W0 闸门**:真实 dsh profile 中 `rm -rf` 进入托管、`/escrow approve` 后真实执行、`/escrow deny` 收到拒绝理由——任一不过,不进入 W1 1. **非阻塞**:红灯入队后 agent 立即继续;模型通过 `escrow_result` 拿到批准后的真实结果(spike 通过前提下;否则此项替换为"sync 增强版行为不回归") 2. **品味**:同一签名第二次起不问;`approve all` 一次批同签名组;不可学习名单动作批准 N 次仍询问 3. **兜底**:`ttlSec:0` 立拒(v0.1.1 已证,回归保持);标记不可补偿的动作在 `release` 策略下超时仍拒绝 4. **自改**:写 `$DSH_HOME` / `AGENTS.md` 被拦为 red;批准后仍不进白名单 5. **减法**:`/escrow reduce` 对注入的重复 fixture 输出正确清单;报告含 SNR-lite 与署名尾注 6. **自身完整**:篡改账本任意历史行后启动告警(哈希链);篡改 `allowlist.json` 破坏 schema 后拒绝加载并告警 7. **性能**:分类器附加延迟 < 1ms(基准测试)