# dsh-compact-receipt · 压缩收据 > ## ⚠️ 测试版(0.4.0-beta.1) > > **默认安装是安全的**:它只记录、审计、拦截,不改变压缩行为。 > > **但“接管压缩”这部分是实验性的,尚未被真实压缩验证过。** 两次端到端测试中压缩都没有触发 > (疑似 `auto` 未开启或阈值下限问题),因此摘要里的“逐字保留块”从未在真实会话中生成过—— > 目前只有单元测试覆盖。 > > 接管默认关闭,需要同时满足:配置 `engine: true` + 禁用 `compaction-basic` 行。 > 在它被真实压缩验证之前,**不建议用于重要会话**。 [English](README.md) | 中文 > 长会话不是记不住,是没人告诉你它什么时候开始忘的。 DSH 的上下文压缩(compaction)是**静默且有损**的:一段历史被换成一条摘要,模型此后只看得见摘要。 你 40 轮前说过的「别动 tests/ 目录」,很可能就在某次压缩里消失了——而没有任何迹象。 这个插件在每次压缩后给你开一张**收据**:这次吃掉了多少、你的哪几条要求消失了。 ``` 本会话共压缩 1 次,最近一次: 收据 #1 · 18:42:07 · 吃掉 24 条历史 (~8.2k tokens) 契约 5 条 · 存活 4 · 疑似失落 1 ⚠️ 疑似失落(摘要里找不到这些要求,建议确认): 1. [约束] 不要改 tests/ 目录 · 第 7 轮 累计存活率: 80% (4/5) ``` ## 为什么不是又一个上下文仪表盘 已有工具在度量上下文**有多大**(`dsh-context`),或者在把它**压得更小**(`billion-context`)。 这个插件度量的是另一件事:压缩之后,**你定下的要求还在不在**。 - 别人优化的是 token 数量,这里审计的是语义保真 - 别人要你手动钉住某段话(`dsh-highlightpin`),这里全自动:装了就有用,零配置 - 审计**不调用模型**:摘要是字符串,要求也是字符串,比对就是字符串比对 → **零 token 成本**,可以每次压缩都跑 ## 安装 ```sh dsh plugin --profile web add github:cty-09/dsh-compact-receipt ``` 重启 DSH 生效。没有配置项,没有开关,装完即用。 ## 用法 | 命令 | 用途 | |---|---| | `/contract` | 最近一次压缩的收据、仍在生效的契约、累计存活率 | | `/contract guard off` | 关闭拦截(默认开启) | | `/contract unblock <编号>` | 解除某一条约束的拦截 | ## 架构(v0.3) ``` 用户消息 ──规则抽取──> 契约表(带 seq) ──┐ ├─ 压缩发生时 被遮蔽原文 ──分类探针──> 钉住体量估算 ──┘ │ 语义判定(ctx.llm) ──失败──> 规则判定(降级) │ 收据 + 补回注入 ──回显验证──> 已确认到达 ``` - **语义分类**:压缩时对被遮蔽消息做**一次批量分类**,把规则漏掉的表达(「tests 目录先别碰」)补进契约表。这是覆盖面从规则转移到模型的关键一步。 - **语义判定**:把「契约清单 + 新摘要」交给模型,一次调用返回 kept/lost/unclear。判定不了就返回 undefined,回退规则并标注「规则判定」,不猜。 - **补回是闭环的**:注入的消息会作为 `user/message` 事件回显,只有回显到了才标「已补回并确认到达」,否则标「补回待确认」。写侧调用成功不等于到达,这一点不混淆。 - **分类探针**:`/contract probe` 只读测量——如果按策略钉住承诺,会钉哪些、占多少上下文。不改任何行为。 - **规则层的准确率是量化的**,不是感觉:`test/corpus.js` 有 21 条标注语料,`npm test` 会打印准确率。当前规则层 **86%**(约束/决策/验收 精确率均为 100%,约束召回 70%)——漏掉的主要是「tests 目录先别碰」这类后置否定,由语义层兜住。 ## 它还会做两件事 **1. 在聊天里直接告诉你。** 压缩丢掉要求时,会话里会出现一张收据卡片:你在 Web 界面就能看到, 不用记着敲命令。这张卡片同时把丢失的要求重新交还给模型——所以它既是提醒,也是成本最低的修复。 ``` 📋 压缩收据 — 这次压缩丢掉了你之前的要求: 1. [约束] 不要改 tests/ 目录,第 7 轮 2. [决策] 用 pnpm,第 3 轮 请继续遵守以上要求;输入 /contract 查看完整收据。 ``` **2. 拦截违规操作。** 记录下「不要改 X」之后,如果 agent 要写入 `X` 路径,这次工具调用会被拒绝, 并回给它一条说明:要么先问你,要么等你执行 `/contract unblock <编号>`。 ``` Blocked by compact-receipt: commit #3 says "不要改 tests/ 目录" (turn 7), and this call targets "tests/unit/app.test.ts". Ask the user to confirm before changing it, or have them run /contract unblock 3. ``` 拦截只覆盖写文件类工具(write/edit/patch/…),不做模糊语义判断——宁可漏拦,不可误拦。 ## 它认哪些「要求」 三类,全部靠规则匹配(中英双语): | 类型 | 例子 | |---|---| | 约束 constraint | 不要改 X、必须用 Y、don't touch Z、must keep W | | 决策 decision | 决定采用 X、就按 Y、we'll use Z | | 验收 acceptance | 验收标准是 X、npm test 必须通过 | 抽取是确定性的:同样的输入永远得到同样的结果,不花钱、不联网、可复现。 ## 诚实的边界 这个插件**不会**假装比它实际更聪明: 1. **「疑似失落」是疑似,不是结论。** 摘要改写了措辞但保住了意思时,可能被误报。判定阈值偏向「宁可多报」——漏报比误报危险。 2. **只审计被压缩的那一段。** 还留在上下文里的要求不会被审计,因为它们本来就没丢。 3. **规则抽取会漏。** 它只认常见的祈使句式,不理解的表达不会被记录。它不猜。 4. **不阻止压缩,也拿不回原文。** 它让你看见损失,并把丢掉的要求重新送回去。 5. **拦截基于路径字符串匹配。** 只认写文件类工具的参数里的路径,不做语义推理;路径写法不同(软链、相对路径)可能漏拦。 6. **那张卡片占 token。** 只在真的丢东西时才出现,通常 4~6 行,远小于它救回来的损失。 7. **没有独立的侧栏面板。** 客户端插件需要自定义打包格式(`window.__ModuleLoader__` + `ctx.slots`)与 React 构建,本版本不包含;当前可见性来自会话内的收据卡片与 `/contract` 命令。 8. **没有接管压缩器。** 接管 `CompactionEngine` 需要重写摘要、范围选择与检查点写入,且只有长会话才会触发、无法在离线环境验证。因此本版本在压缩边界上提供可验证的保证(补回 + 回显确认),而不是替换引擎。 ## 工作原理 DSH 在压缩时写入 `compaction/summary` 事件,其中带有摘要正文和被遮蔽的历史序号。 插件订阅会话事件流,在用户消息进来时抽取要求,在压缩发生时把这些要求与摘要正文做重叠度比对。 审计的比对方式:英文标识符/路径/反引号内容做精确匹配,中文按字符二元组计算重叠率,两者取均值。 没有模型调用,没有网络请求,没有额外 token。 ## 开发 ```sh npm test # 20 个用例,含端到端模拟 ``` 零依赖、零构建步骤:`lib/` 里的 ESM 就是发布物。 > 为什么一个 import 都没有:`@deepseek-ai/*` 运行时包只存在于 DSH 安装目录,profile 里没有,DSH 也不注册 ESM 解析钩子。第三方插件只要 `import` 它们,在用户机器上就会 `ERR_MODULE_NOT_FOUND`。所以这里只用 `ctx`,不引入任何宿主包。 ## License MIT