dsh-engram 0.7.4 → 0.8.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +93 -6
  2. package/README.zh.md +6 -2
  3. package/docs/CONTEXT-GC-GUIDE.zh.md +15 -1
  4. package/docs/G6-quality-ab.zh.md +540 -0
  5. package/docs/GATES.zh.md +41 -0
  6. package/docs/PROPOSAL-evolution.zh.md +12 -0
  7. package/docs/RELEASE-NOTES-v0.7.10.md +49 -0
  8. package/docs/RELEASE-NOTES-v0.7.11.md +31 -0
  9. package/docs/RELEASE-NOTES-v0.7.12.md +22 -0
  10. package/docs/RELEASE-NOTES-v0.7.13.md +41 -0
  11. package/docs/RELEASE-NOTES-v0.7.14.md +37 -0
  12. package/docs/RELEASE-NOTES-v0.7.15.md +36 -0
  13. package/docs/RELEASE-NOTES-v0.7.16.md +42 -0
  14. package/docs/RELEASE-NOTES-v0.7.5.md +134 -0
  15. package/docs/RELEASE-NOTES-v0.7.6.md +74 -0
  16. package/docs/RELEASE-NOTES-v0.7.7.md +60 -0
  17. package/docs/RELEASE-NOTES-v0.7.8.md +56 -0
  18. package/docs/RELEASE-NOTES-v0.7.9.md +46 -0
  19. package/docs/RELEASE-NOTES-v0.8.0.md +59 -0
  20. package/docs/RELEASE-NOTES-v0.8.1.md +70 -0
  21. package/docs/RELEASE-NOTES-v0.8.2.md +62 -0
  22. package/docs/RELEASE-NOTES-v0.8.3.md +65 -0
  23. package/docs/RELEASE-NOTES-v0.8.4.md +56 -0
  24. package/docs/RELEASE-NOTES-v0.8.5.md +60 -0
  25. package/docs/RELEASE-NOTES-v0.8.6.md +71 -0
  26. package/eval/gate-audit.mjs +538 -0
  27. package/lib/api.js +70 -0
  28. package/lib/approvals.js +84 -0
  29. package/lib/boundary-prune.js +71 -5
  30. package/lib/capsule.js +134 -0
  31. package/lib/capture.js +83 -5
  32. package/lib/client.js +66 -0
  33. package/lib/compaction.js +4 -11
  34. package/lib/context-gc.js +63 -2
  35. package/lib/index-block.js +79 -4
  36. package/lib/index.js +91 -18
  37. package/lib/ledger.js +200 -10
  38. package/lib/pack-telemetry.js +10 -3
  39. package/lib/prune.js +89 -0
  40. package/lib/session-events.js +44 -2
  41. package/lib/skill-export.js +289 -0
  42. package/lib/status-insights.js +5 -0
  43. package/lib/status.js +138 -0
  44. package/lib/store.js +34 -0
  45. package/lib/usage.js +32 -3
  46. package/lib/web-provision.js +59 -14
  47. package/package.json +15 -8
  48. package/scripts/dsh-engram.mjs +229 -4
@@ -0,0 +1,59 @@
1
+ # dsh-engram v0.8.0
2
+
3
+ **v0.8-A:procedure 变成有证据的东西。** 这一版只做 A(证据化 procedure + 失效检测);
4
+ B(导出 DSH Skill)、C(subagent 胶囊)、D(审批门)还没做。
5
+
6
+ ## 1. 之前的问题
7
+
8
+ `fixed: npm test — 1 earlier failing run now succeed` 这类 procedure 是**一次成功就写进去、
9
+ 一次成功就进索引**的。那不是经验,那是运气。`signal 0.45 ≥ minIndexSignal 0.4`,
10
+ 所以它当场就占了 [ENGRAM] 的一行——正是「从 n=1 泛化」的教科书反例。
11
+
12
+ ## 2. 现在
13
+
14
+ | 字段 | 含义 |
15
+ |---|---|
16
+ | `evidenceCount` | verified 成功次数。诞生时 = 1 |
17
+ | `lastVerifiedAt` | 最后一次 verified 成功的时间 |
18
+ | `lastFailedAt` | 最后一次同命令失败的时间 |
19
+ | `invalidatedBy` | 导致失效的那条 error 记忆 id |
20
+
21
+ **晋升**:`evidenceCount ≥ 3` **且** 最近验证在 14 天内 **且** 之后没失败 → 才进索引。
22
+ 一个手写的 procedure(没有 evidence 字段)继续走老的 `hits >= promoteHits`,不会被新门误伤。
23
+
24
+ **失效**:同命令再次失败 → 立刻 `lastFailedAt = now`、`invalidatedBy = <error id>`、
25
+ `signal → 0.2`、**当场退出索引**。理由很直接:一条刚失效的 procedure 比没有更糟,
26
+ 下一个 agent 会照着抄。
27
+
28
+ **记账不碰 recency**:`recordProcedureOutcome` 不改 `updatedAt` / `hits`——
29
+ 证据不是召回,crediting 一次成功不该把这条记忆在时间序里重新排前。
30
+
31
+ ## 3. 接在哪
32
+
33
+ `lib/capture.js` 的 auto-capture handler:每一次命令运行都会问
34
+ `procedureOutcome()`(同 workspace、同 `cmd:` 签名、active、`fixed:` 前缀),
35
+ 命中就记一笔证据。**没有新记忆要写的时候也记**——大多数命令运行本来就不产生记忆,
36
+ 而它们恰恰是证据的主体。三条早退路径(无条目、窗口内重复、正常写入)都会走到这笔账上。
37
+
38
+ ## 4. 门的证据
39
+
40
+ `npm run playbook:audit`([eval/playbook-audit.mjs](eval/playbook-audit.mjs))跑一个
41
+ **注入测试**:往空 store 里塞 10 条「看起来权威」的 `fixed:` procedure。
42
+
43
+ | 阶段 | 期望 | 实测 |
44
+ |---|---|---|
45
+ | 过时(30 天未验证)时在索引里 | 0 | 0 |
46
+ | 刚重新验证后(对照) | 10 | 10 |
47
+ | 首次再失败后失效 | 10 | 10 |
48
+ | 失效后仍在索引里 | 0 | 0 |
49
+
50
+ **10/10 PASS。** 提案里写的是「7 天内全部被降权/失效」——机制是首次失败即失效,
51
+ 所以测试直接注入失败,不必等一周。
52
+
53
+ 线上账本(报告不判定):27 条 procedure,2 条 auto-captured(都未证明、都在索引外),
54
+ 4 条靠 hits 晋升的手写 procedure,0 条失效。
55
+
56
+ ## 5. 还没测的
57
+
58
+ - **复用率 ≥30%**:需要「被召回后真的被引用」的遥测,现在只有晋升/失效计数;
59
+ - **一次通过率 +5%**:属于 G6,装置已就绪(`npm run quality:ab`),缺一次真实配对实验。
@@ -0,0 +1,70 @@
1
+ # dsh-engram v0.8.1
2
+
3
+ **v0.8-B:验证过的 procedure 可以导出成真正的 DSH Skill。**
4
+
5
+ ## 为什么
6
+
7
+ v0.8.0 让 procedure 有了证据。但一条 `[ENGRAM]` 行只是提示:会话压缩后它就不在了,
8
+ subagent 也看不到它。DSH Skill 是另一层表面——宿主从 `.dsh/skills` 发现它、在会话
9
+ catalog 里挂上名字、任何 agent 都能按需加载**全文**。被验证 3 次的东西,应该是一个
10
+ 真实产物,而不是一行会被压掉的回忆。
11
+
12
+ ## 怎么用
13
+
14
+ ```bash
15
+ npx dsh-engram skill export # → <workspace>/.dsh/skills/<name>/SKILL.md
16
+ npx dsh-engram skill export --dry-run # 只看计划,不落盘
17
+ ```
18
+
19
+ 导出的是 `engram-fix-<command>`,正文包含:验证次数、首次捕获与最近验证时间、
20
+ 它闭合的那次失败签名(同命令最新的 resolved error,最多 3 行)、以及"这条是证据不是
21
+ 保证——先跑一遍"的使用说明。
22
+
23
+ ## 三条安全规则
24
+
25
+ 1. **只导出过门的**:≥3 次验证、14 天内验证、未失效。手写的 procedure(只有 hits)
26
+ 不会被导出——召回次数不是验证次数。
27
+ 2. **只碰自己的文件**:每个 SKILL.md 带 `generated-by: dsh-engram skill-export` 标记;
28
+ 没有标记的同名文件一律跳过(人写的技能永远不被覆盖)。
29
+ 3. **失效即消失**:procedure 不再成立(失效/过期/归档)后,下一次 export 会把它的
30
+ SKILL.md 删掉——catalog 不能继续推荐一条刚坏掉的修法。
31
+
32
+ ## 宿主契约是核实过的,不是猜的
33
+
34
+ 读的是 `@deepseek-ai/dsh-skill-filesystem` 源码:
35
+
36
+ - 根目录优先级:`<project>/.dsh/skills` (100) → `<project>/.agents/skills` → custom →
37
+ `$DSH_HOME/skills` → `$AGENTS_HOME/skills` → bundled;
38
+ - 一个技能 = 含 `SKILL.md` 的目录(或平铺 `*.md`);
39
+ - frontmatter 必须有 `name` + `description`,`name` 匹配 `/^[a-z0-9]+(?:-[a-z0-9]+)*$/`;
40
+ `whenToUse`、`disable-model-invocation`、`user-invocable` 可选;
41
+ - 根目录有 watcher,新文件不需要重启 dsh。
42
+
43
+ ## 证据
44
+
45
+ `npm run skill:check` 不走我们自己写的解析器——它 **import 宿主自己的 provider**
46
+ (`FileSystemSkillProvider.list()` / `.get()`),在临时工程里验证 11 条:
47
+
48
+ ```
49
+ ✓ promoted procedure is advertised by the host
50
+ ✓ unproven row is not exported
51
+ ✓ invalidated row is not exported
52
+ ✓ hand-written skill survives
53
+ ✓ stale generated skill was swept
54
+ ✓ second export is a no-op
55
+ ✓ host parses description
56
+ ✓ host parses whenToUse
57
+ ✓ host loads the full body
58
+ ✓ name matches the host grammar
59
+ ✓ model-invocable + user-invocable by default
60
+ ```
61
+
62
+ 单测:`test/skill-export.test.mjs` 8 条(命名文法、门规则、失败签名取最新 resolved、
63
+ 幂等、人类文件不被覆盖、失效即删、dry-run 不落盘)。全量 `npm test` 463/463。
64
+
65
+ ## 还没做的
66
+
67
+ - v0.8-C(subagent 交接胶囊)、v0.8-D(审批门)还没动;
68
+ - 导出目前是 CLI 触发的,插件内部还没有"晋升时自动导出"的钩子;
69
+ - 真实账本里这个 workspace 还没有过门的 auto procedure,所以本机暂时导不出东西——
70
+ 机制已用合成数据验证,等真实 procedure 自然晋升后即可用。
@@ -0,0 +1,62 @@
1
+ # dsh-engram v0.8.2
2
+
3
+ **v0.8-C(能做的部分):subagent 交接胶囊——留档做全了,替换做不了,理由写在代码里。**
4
+
5
+ ## 提案想要的
6
+
7
+ > 子代理结束时,父代理只收一条 ≤500 tok 的胶囊:结论、证据、未决问题、建议下一步。
8
+
9
+ ## 为什么这一版只做了一半
10
+
11
+ 去读了宿主的结果路径:`dsh-tools` 的 `notifyResult()` 把 `tools/result` 用
12
+ `ctx.events.dispatch("emit", …)` 发出去,函数自己的注释写着 *"Notify observers
13
+ without exposing a mutation or error channel into the outcome"*——**监听者改不了父代理
14
+ 读到的东西**。所以"父代理只收胶囊"需要一个宿主目前没有的接缝。
15
+
16
+ 能做且做了的是另一半,而且它是真的:
17
+
18
+ - 子代理报告 ≥ `capsuleMinSourceChars`(1500)字时,用**纯结构规则**(标题、列表、
19
+ 问号、next/未决线索)抽成胶囊,存成 `handoff` 记忆;
20
+ - 子代理会话结束后结论不再随会话蒸发——压缩、跨会话、`engram_recall` 都能捞到;
21
+ - 胶囊自己在脚注里写清 `源 → 胶囊` 字符数,所以"如果替换能省多少"是**可测的**,
22
+ 不是拍脑袋的。
23
+
24
+ ## 胶囊长什么样
25
+
26
+ ```
27
+ **结论**:The recall benchmark reranks by recency and the fix is a stable tie-break.
28
+ **证据**:
29
+ - tests pass 184/184 after the change (npm test)
30
+ - touched lib/rerank.js and test/rerank.test.mjs
31
+ **未决**:
32
+ - open question: should BM25 weight decay with age?
33
+ **下一步**:
34
+ - next step: measure the CI wall-clock delta
35
+
36
+ ---
37
+ 胶囊:rerank review 1770 → 849 字符;全文在子代理会话日志里(可用 session 搜索回取)。
38
+ ```
39
+
40
+ 没有结构可提炼时它**不假装总结**:保留首尾 + 标明省略;而且有一条硬规则——
41
+ 胶囊永远不会比原文更长(否则退化成保证更小的首尾截断)。
42
+
43
+ ## 顺手加的
44
+
45
+ `npx dsh-engram status` 现在报当前 workspace 的 playbook 与胶囊计数:
46
+
47
+ ```
48
+ playbook(当前 workspace):13 条 procedure · 过门 0 · 未过门 13 · 失效 0
49
+ subagent 胶囊:N 条 · 源 → 胶囊 字符(只做留档,父代理仍收到全文)
50
+ ```
51
+
52
+ ## 证据
53
+
54
+ - `test/capsule.test.mjs` 7 条:结论/证据/未决/下一步抽取、无结构保留首尾、
55
+ maxChars 上限、胶囊不长于原文、resultText 三种形状、长报告入库、短报告不入库;
56
+ - 全量 `npm test` **470/470**。
57
+
58
+ ## C 的后半段要等什么
59
+
60
+ 如果宿主将来暴露"结果变换"接缝(或在 `toolResultPruner` 上给出可插拔的渲染),
61
+ 胶囊就能从留档升级成真正的替换;在那之前,任何"父代理上下文变小"的说法都是假的。
62
+ D(审批门)也还没动。
@@ -0,0 +1,65 @@
1
+ # dsh-engram v0.8.3
2
+
3
+ **v0.8-D:审批门——证据让你进索引,人点头才让你写文件。**
4
+
5
+ ## 为什么两种表面要用两种门
6
+
7
+ v0.8-A 的门是证据:同一命令成功 ≥3 次、14 天内、未失效 → 进 `[ENGRAM]` 索引。
8
+ v0.8-B 把过门的 procedure 写成 `SKILL.md`,宿主会把它挂进**每个**会话的 catalog。
9
+
10
+ 这两件事的风险不一样:
11
+
12
+ | 表面 | 成本 | 后果 | 门 |
13
+ |---|---|---|---|
14
+ | 索引里的一行 | 几十字符,下轮就没了 | 私有、可撤回 | 证据(自动) |
15
+ | `.dsh/skills` 里的文件 | 磁盘文件 | 被宿主广告给所有 agent(含 subagent) | 证据 **+ 人点头** |
16
+
17
+ **证据证明的是一条命令跑通过,不是这条指令是对的。** 三条成功记录也可能是三条
18
+ 有害记录——所以写文件这件事,机械证据不够。
19
+
20
+ ## 怎么用
21
+
22
+ ```bash
23
+ npx dsh-engram skill pending # 证据已够、等你批准的清单
24
+ npx dsh-engram skill approve <id> # 点头(可带 --note "…")
25
+ npx dsh-engram skill revoke <id> # 收回,下次 export 会删掉它的 SKILL.md
26
+ npx dsh-engram skill export # 只导出「过证据门 + 已批准」的
27
+ npx dsh-engram skill export --force # 本次跳过批准门(审计用的逃生口)
28
+ ```
29
+
30
+ 批准记录存在 `~/.dsh/engram/playbook-approvals.json`,**不放进记忆库**——批准是人的动作,
31
+ 放进同一个池子里就等于让池子自己批准自己。结构:
32
+
33
+ ```json
34
+ { "version": 1, "workspaces": { "/path/to/repo": { "<memoryId>": { "at": 1792…, "note": "看过了" } } } }
35
+ ```
36
+
37
+ `pending` 与 `export` 用的是同一个 `planSkillExport`,所以「清单里有的」和「导出时被拦的」
38
+ 永远是同一批——不会出现清单说 A 够格、导出却默默跳过 A 的分叉。
39
+
40
+ ## 你会看到的
41
+
42
+ ```
43
+ $ npx dsh-engram skill export
44
+ skill export · workspace /repo · 128 条记忆 · 目标 /repo/.dsh/skills
45
+ 等批准 1(证据已够,但写文件需要你点头):
46
+ engram-fix-npm-test a1b2c3d4
47
+ 批准:npx dsh-engram skill approve <id>;或本次强制:--force
48
+ ```
49
+
50
+ ## 证据
51
+
52
+ - `test/approvals.test.mjs` 5 条:文件缺失即零批准、按 workspace 隔离、撤销后空桶清理、
53
+ 文件损坏降级为「没有批准」而不是崩、空 id 拒绝;
54
+ - `npm run skill:check` 从 11 条扩到 **15 条**,新增 4 条走的是宿主自己的 provider:
55
+ 未批准不落文件、未批准进 pending、批准后能导出、`--force` 能绕过;
56
+ - 全量 `npm test` 见下。
57
+
58
+ ## 边界(写清楚,免得被当成已做)
59
+
60
+ - 只挡住了「写文件」这一层。索引里的 procedure 行仍是证据门自动晋升的——它便宜、私有、
61
+ 撤回无成本,加审批只会让人学会无脑点「同意」;
62
+ - 审批记录是**本机**状态,不进 git:换机器要重新点头。这是有意的——跨机复制批准等于
63
+ 把「我看过了」变成「有人看过了」;
64
+ - GUI 里还没有审批按钮(只有 CLI)。面板要做的话,读的是同一个 approvals 文件,
65
+ 不需要新协议。
@@ -0,0 +1,56 @@
1
+ # dsh-engram v0.8.4
2
+
3
+ **v0.8-D 的另一半:审批门有了 GUI;G6 的门方向修正 + 隐藏规格语料。**
4
+
5
+ ## 1. GUI 审批(`GET|POST /api/dsh-engram/approvals`)
6
+
7
+ CLI 里能批,面板里也能批,而且是**同一份记录、同一个规划器**:
8
+
9
+ - 服务端 `approvalsView()` 用 `planSkillExport`(`skill export` 用的同一个)算出
10
+ 「证据过关的 procedure」,再按 `~/.dsh/engram/playbook-approvals.json` 切成
11
+ approved / pending。**GUI 不可能批准一个 CLI 会跳过的条目**——两边不是各写一遍规则。
12
+ - 客户端「记忆」页顶部出现「Playbook 待批准」卡片:名字、id、证据次数、描述 + 批准/撤销按钮。
13
+ - 撤销不是删除证据:条目退回 pending(证据还在,只是文件又被撤了)——这正是操作者
14
+ 需要看到的状态。
15
+
16
+ 顺手修的两处:
17
+
18
+ - `planSkillExport` 的 `dir` 现在是可选的(GUI 只问「会写什么」,不落地),
19
+ 传 `undefined` 不再炸在 `path.join` 上;
20
+ - `requireApproval: true` 只返回**已批准**的条目,所以「待批准列表」必须用
21
+ `requireApproval: false` 再按批准记录切分——这条写进代码注释,因为第一次写错就是这么错的。
22
+
23
+ ## 2. G6 的门方向修正(重要)
24
+
25
+ 原来的门是 `|Δ| ≤ 2pp`,等于「记忆帮了忙也算失败」。改成单边:
26
+
27
+ | 条件 | 判定 | 含义 |
28
+ |---|---|---|
29
+ | Δ ≥ −2pp | PASS | 不伤害(**硬条件**) |
30
+ | Δ > +2pp | PASS + 观测值 | 记忆带去了可用信息(提案的愿望,不是门槛) |
31
+ | Δ < −2pp | FAIL | 挂载让任务变差 |
32
+ | 配对 < 10 | 未测 | 低于配对下限一律不判 |
33
+
34
+ 修正发生在第一轮 0.0pp 之后、第二轮之前——不是为了让某个结果过关,而是把
35
+ 「愿望」写进门槛本身就说反了。`npm test` 里两条新用例分别钉住「+100pp 判 PASS」
36
+ 和「−100pp 判 FAIL」。
37
+
38
+ ## 3. 隐藏规格语料(G6 第二轮)
39
+
40
+ 第一轮 12/12 vs 12/12 是天花板:测试就在仓库里,两臂都能读到规格。
41
+ 第二轮(`eval/fixtures/ledger-kata-hidden`)仓库只有 `src/`,**测试在仓库外**,
42
+ `check` 在 agent 收工后才把私有测试拷进去;规格只存在于预置记忆(6 条约定 + 2 条过时旧约定)。
43
+
44
+ 控制组不许偷看,是**物理隔离**而不是靠自觉:
45
+
46
+ - 控制臂运行时把记忆库文件移出 `DSH_HOME`(移到系统临时目录,跑完移回)——
47
+ 第一次只把文件改名为 `.g6-hidden` 留在原目录,agent 直接 `ls storages/` 读走了;
48
+ - 跑批输出目录搬到仓库外,否则 agent 顺着 `..` 就能读到 `eval/g6/oracle/` 和种子文件;
49
+ - harness 对控制组日志做污染检测(`dsh_engram` / `[ENGRAM]` / `engram_recall`),
50
+ 报告里计数——一个跑出漂亮数字的 pilot 差点被当成证据,这条是那次教训的产物。
51
+
52
+ ## 证据
53
+
54
+ - `npm test` **477/477**(本轮 +2:审批 API 往返、门方向)
55
+ - `npm run skill:check` PASS 15/15
56
+ - G6 第二轮结果见 `docs/G6-quality-ab.zh.md`(有效数据 + 天花板声明)
@@ -0,0 +1,60 @@
1
+ # dsh-engram v0.8.5
2
+
3
+ **一条实验驱动的改动:记忆指向的文件变了,行上会写出来。**
4
+
5
+ ## 反向实验发现了什么
6
+
7
+ `docs/G6-quality-ab.zh.md` §9:同一个仓库,代码里有 bug、docstring 写着正确约定,
8
+ 预置记忆换成 5 条**过时的错误约定**。6 个任务里 agent 有 1 个照抄了错记忆并挂掉——
9
+ 不是随机失手,它在日志里先写下「audit log 通常是 UTC」,然后用仓库里那句
10
+ 「按团队口径写」说服自己服从记忆。
11
+
12
+ 另外 5 个任务里,agent 靠**记忆行上的日期**(`2026-09 记录`)判断出这条是旧的。
13
+ 所以日期不是装饰,是可被用来降权的证据——索引行和召回行本来就带 `createdAt`。
14
+
15
+ ## 这次补的口子:`filePath` 但没有 anchor 的记忆
16
+
17
+ 已有的一半:带 anchor 哈希的记忆,文件变了会直接掉出索引(`memoryIsStale`)。
18
+ 但还有一批记忆只是**提到**某个文件(本仓库 402 行里 62 行有 `filePath`),
19
+ 它们没有任何信号告诉模型「这行写的文件后来被改过」。
20
+
21
+ 现在索引行和 `[RECALL]` 行会带一个标记:
22
+
23
+ ```
24
+ [D] 09-14 …… #9b585a1b ⚠file-changed
25
+ [D] 08-02 …… #61c0ffee ⚠file-missing
26
+ ```
27
+
28
+ - `⚠file-changed`:锚定文件的 mtime 晚于记忆的 `createdAt`
29
+ - `⚠file-missing`:文件已不存在(比「什么都没说」诚实)
30
+ - 没有 `filePath`、没有时间戳、stat 失败 → 什么也不加,且**永不抛错**(注入路径不能因为一个坏路径炸掉)
31
+
32
+ 一次 `stat` 换一个可核实的信号;20 行索引对它来说不算成本(G7 仍远低于 0.5%)。
33
+
34
+ ## 证据
35
+
36
+ - `npm test` **481/481**(+4:changed / unchanged / missing / 无锚点不抛)
37
+ - G6 反向实验:`eval/g6/runs/stale-a/REPORT.md`(12 对,复制率 1/6)
38
+
39
+ ## 附:G6 的 +30pp 已撤回(同日深夜)
40
+
41
+ 第三轮用 macOS seatbelt 做了内核级读黑名单(`--sandbox`),同一语料重跑:
42
+ **Δ 从 +30.0pp 缩到 +8.3pp**(12 对,控制臂平均耗时 743s → 116.5s)。原因不是数字
43
+ 挑拣,是第二轮的环境同时污染两臂、方向不明——控制臂把时间花在找泄漏上。
44
+ 更关键的发现:这个语料的「规格」其实写在 `src/*.js` 的 docstring 里,
45
+ **不满足「不可推导」**,测不出记忆价值。
46
+
47
+ 详见 `docs/G6-quality-ab.zh.md` §10。G6 门槛本身没变(Δ ≥ −2pp),仍 PASS;
48
+ 变的是我们对「记忆带来多少提升」的表述:现在是「不伤害 + 1 对配对的方向性证据」。
49
+
50
+ ## 再附:第四轮把 G6 做成了真实验(2026-10-27 凌晨)
51
+
52
+ 第三轮的语料规格写在 docstring 里,测不出记忆价值。第四轮换成
53
+ `eval/fixtures/ledger-kata-blind`——**规格物理上不在仓库里**(任意校验算法、任意错误码前缀、
54
+ 「四舍五入远离零」、降序稳定排序),只有种子记忆写着约定。
55
+
56
+ 12 对(4 任务 × 3 种子,seatbelt 围栏):**带记忆 12/12,不带 5/12,Δ = +58.3pp**。
57
+ 在三条真正不可推导的约定上:控制臂 2/9,带记忆 9/9。耗时 131.8s vs 208.1s。
58
+
59
+ 期间又抓到两个泄漏(`/tmp` 与 `/private/tmp` 的 deny 不等价;判完不删 oracle),
60
+ 修完重跑受影响的 6 次控制,Δ 不变。详见 `docs/G6-quality-ab.zh.md` §11。
@@ -0,0 +1,71 @@
1
+ # dsh-engram v0.8.6
2
+
3
+ **桌面宿主上那三个「一直在休眠」的特性,修好了;顺手把「静默」改成会说话。**
4
+
5
+ 这是 0.8.x 第一次发布到 npm(上一版 npm `latest` 还是 `0.7.4`),
6
+ 所以从 npm 升级的用户这一跳是 `0.7.4 → 0.8.6`,`0.8.0`–`0.8.5` 的内容一起到达——
7
+ 见文末「0.8.0–0.8.6 一次性带给你什么」。如果你只是想知道自己踩的坑修没修:
8
+ **issue #9 修了**。
9
+
10
+ ## 修复:宿主没有批量读接口时,退回逐条读
11
+
12
+ `episode`(会话沉淀)、`[RESUME]` 简报、`[RECALL]` 启动召回、会话结束的 todo sink,
13
+ 四件事都读会话事件日志。`lib/session-events.js` 原本有三手:
14
+
15
+ 1. `session.events`(DSH ≤0.1.x 的旧字段)
16
+ 2. `ctx.sessionQuery.live()`(≥0.2.x 的正规租约)
17
+ 3. `session.snapshotEvents()`(宿主已标 deprecated 的同步批量读)
18
+
19
+ Windows 桌面运行时(`@deepseek-ai/dsh-desktop-runtime` 0.2.1-rc.2)**三样都没有**,
20
+ 于是四项特性一起休眠,且没有任何配置能绕过。issue #9 的报障就是这么来的。
21
+
22
+ 现在有第四手:
23
+
24
+ 4. **`session.seq` + `session.eventAt(seq)`** —— 逐条读。这是上面所有批量读底下
25
+ 的原语,宿主可以砍掉批量接口而留下它。慢一点,但能让特性活着。
26
+
27
+ 顺序不变,前一手能用就不走后面;`sessionEventsSource()` 也把 `"eventAt"` 报进状态,
28
+ `/stats` 与冒烟检查都能看见这一轮到底走了哪条路。
29
+
30
+ ## 「静默休眠」本身也是 bug
31
+
32
+ 报障的同学是解 `session.v4.jsonl.zstd` 的帧才确认「不是还没触发,是根本不会触发」的。
33
+ 这个成本不该由用户付。两处改进:
34
+
35
+ - 休眠时的 warn 现在**报出它有什么**:
36
+ `… no session.events, no ctx.sessionQuery, no snapshotEvents, no eventAt … Session surface: seq, eventAt, append`
37
+ —— 下一份报障带上这一行,就能直接判定对面是哪代宿主。
38
+ - README 的 episode 小节加了明确的宿主要求段:哪些接口能满足、三样都没有时会休眠、
39
+ 以及存储与 `engram_recall`/`engram_detail` 仍然照常工作。已知案例点名桌面运行时。
40
+
41
+ ## 证据
42
+
43
+ - `npm test` **483/483**(新增:只有 `seq`+`eventAt` 也能读出日志、episode 仍能生成、
44
+ 完全没有可读接口时 `sessionEventsSource === "none"` 且 surface 探测能报出它有什么)
45
+ - `npm run typecheck` 通过;`prepublishOnly` 真实打包 + 装上 peers 后 host/client 双入口导入通过
46
+ - G6 第五轮(同批):**20 对配对,Δ = +90.0pp**(带记忆 20/20,裸臂 2/20),
47
+ 在三条不可推导约定上 15/15 vs 0/15 —— 见 `docs/G6-quality-ab.zh.md` §12
48
+
49
+ ## 0.8.0–0.8.6 一次性带给你什么(相对 npm 上的 0.7.4)
50
+
51
+ - **0.8.0 证据化 procedure** — procedure 记忆要带「验证过」的证据才进索引,并有失效检测
52
+ - **0.8.1 Skill 导出** — 验证过的 procedure 能导出成真正的 DSH Skill
53
+ - **0.8.2 subagent 交接胶囊** — 留档做全(替换做不了,理由写在代码里)
54
+ - **0.8.3 审批门** — 证据让你进索引,人点头才让你写文件
55
+ - **0.8.4 审批门 GUI + G6 门方向修正** — 单边门(Δ ≥ −2pp)与隐藏规格语料
56
+ - **0.8.5 记忆行上的文件信号** — `⚠file-changed` / `⚠file-missing`,让「这条记忆指向的文件变过」可见
57
+ - **0.8.6 本版** — issue #9 修复 + 休眠不再静默
58
+
59
+ 逐版细节见 `docs/RELEASE-NOTES-v0.8.{0,1,2,3,4,5}.md`。
60
+
61
+ ## DSH 版本支持(必填)
62
+
63
+ - **支持的 DSH 范围**:`>=0.1.2-alpha.2 <0.3.0-0`
64
+ - **验证版本**:`dsh 0.2.1-rc.2`(本机 CLI + web,`dsh --version`)
65
+ - **最后验证日期**:2026-10-27
66
+ - **安装方式已验证**:`prepublishOnly` 用真实 tarball 装 peers 后导入 host/client 双入口
67
+ - **peer 声明**:`@deepseek-ai/dsh-{settings,storage-domain,compaction,compaction-basic,llm}@>=0.1.2-alpha.2 <0.3.0-0`、`@deepseek-ai/cordis@^4.0.2`、`@deepseek-ai/schemastery@^3.18.2`
68
+
69
+ > 已知限制:桌面运行时(`@deepseek-ai/dsh-desktop-runtime`)若不暴露
70
+ > `sessionQuery` / `snapshotEvents` / `eventAt` 中的任何一个,四项注入特性仍会休眠
71
+ > (存储与工具不受影响),此时请把 warn 里的 `Session surface:` 一行贴进 issue。