# dsh-study-buddy 更新记录
> 版本基线:v1.1.1 | 协议:MIT | 读者:使用者、插件维护者
>
> **逐版变更的唯一来源**:根 [`README.md`](../README.md) 首屏只留一行版本号,详细条目在这里维护
> (口径单一来源,见 [`docs/README.md`](README.md) §三)。
> 版本号改动是**最后一刀**:`package.json` 与 `dsh.plugin.json` 必须一致,现行文档的头部基线由
> `tests/docs.spec.ts` 校验;模块数/测试项数由同一条测试从 `src/`、`tests/` 现算比对。
---
## v1.1.1(2026-09-25)— v4 来源准入拦下开场门禁:首条消息整轮失败
起因:DSH 升到 **0.1.7-rc.2** 后,「学习伙伴」会话的**首条消息必然失败**——界面上只有
`本轮运行失败 format v4 message requires a producer-owned source kind`,用户消息也不落盘
(会话日志止于 `turn/start`,`sessionStats.turns` 仍是 0)。
**取证**(三条都对上才算定案):
1. 插件唯一的注入点是 `src/opener.ts` 的预步提醒,来源写的是**退场的包装**
`{ kind: 'plugin', plugin: 'dsh-study-buddy' }`(产物 `lib/index.js`,与 profile 安装副本哈希一致)。
2. 平台 0.1.7 的 **v4 会话格式**在 `packages/session/session-format-v3-to-v4/src/message-sources.ts`
加了硬准入:`source.kind` 必须是非空字符串且**不得**是 `'plugin'`。该检查挂在 `codec.encodeEvent`
上,而它就是线上写盘路径(`session-format-catalog` → `format.eventLine`)——所以异常冒泡成
**整轮失败**,而不是"少注入一次提醒"。平台自己的注释也写死了这条口径:
*"each producer declares its own `kind`; there is no shared catch-all `plugin` kind"*。
3. 复现与验证都用**活平台**:把产物真的注入的提醒对象喂给本机运行中的
`releasedV4SessionFormatCodec.encodeEvent` → 复现原文错误;把 kind 换成 `plugin:dsh-study-buddy` → 通过。
平台自己的 V3→V4 迁移对本插件的映射也正是这个值(README:「Any other plugin name → `plugin:` + 原名」),
因此**新旧行仍是同一个生产者身份**。
**修复**:
1. **`src/opener.ts`:来源改为生产者自有 kind**(`OPENER_SOURCE_KIND = 'plugin:dsh-study-buddy'`),
并去掉退场的 `plugin` 字段;顺带按平台 `ContextFormed` 惯用法补 `form: 'notice'` + `summary`
(对话里折叠成一行,与 `repeat-tool-reminder` / `plan-mode` 同款;缺 `summary` 会退回不透明展开体)。
2. **`src/host.ts`:新增第 6 个契约点 `messageSourceKind`**(平台坐标 + 失效后果 + 改哪里),
让"平台再动这里"能被排障表与探针直接指到。
3. **测试**:`tests/opener.spec.ts` 新增「v4 来源准入」回归(kind 非空 / ≠ `plugin` / == `plugin:<包名>` /
无 `plugin` 字段 / `notice` 带非空 `summary`);`tests/apply.spec.ts`、`tests/contract.spec.ts` 的注入断言同步。
测试 292 → 293 项。
4. **探针**:`tools/verify-contract.mjs` 增一条**常跑**断言(不依赖平台包,任何机器/CI 都有增量)
+ 一条**活平台**断言(把真实注入对象喂给平台的 v4 行编码器,退场包装必须被拒——自带负向对照);
`--self-test` 增第 7 例(把注入来源改回退场包装必须报错);新增 `--platform
` 覆盖平台解析根
(DSH 从源码树跑时平台包只在 `.pnpm/node_modules` 里可解析)。
5. **文档**:技术文档 §6/§8/§9 同步(含该错误签名的排查入口);用户指南 §11.1、升级后验收清单同步;
经验文档 §十二记录本轮教训;`docs/archive/dev-experience/` 里那条"旧来源仍合法"的核查结论加失效标注。
## v1.1.0(2026-09-24)— 目录式预设被平台删除:迁成声明式 bundle
起因:DSH 升到 **0.1.7-rc.1** 后「学习伙伴」预设与 18 个工具**整体消失,且没有任何报错**。
取证结论:平台提交 `d1e22a7e24 / #4569 feat(preset): declare Agent compositions in profile YAML`
**删除了目录式预设**——`$DSH_HOME/.agent-presets//` 再没有读者(`T:\deepseek-harness\packages`
全量 grep `.agent-presets` 零命中;官方技能 `cordis-composition-reference` 的迁移一节原文
*"Nothing reads that directory any more"*)。插件代码与平台契约探针(13 条)全绿,坏的只是**交付形态**。
1. **交付形态改为声明式 bundle(`package.json` / 新增 `presets/study.patch.yml`)**:新增
`dsh.bundle.patch: ./presets/study.patch.yml`,内插一条 `preset-study`(`@deepseek-ai/dsh-agent-preset`)
声明,`config.plugins` 由原 `presets/study/agent.cordis.yml` **原文照搬**;`presets/study/{agent.cordis.yml,preset.yml}`
删除(skill 资产与期望模板留在 `presets/study/`)。技能路径改用官方同款惯用法从**已安装包**解析
(`createRequire(baseUrl).resolve('dsh-study-buddy/package.json')` → `presets/study/skills`)。
2. **`vaultRoot` 出包(新增 `src/config.ts`)**:包要开源、多机共用,机器路径不进仓库。四级来源
**行 config > `DSH_STUDY_VAULT`(别名 `DSH_VAULT_ROOT`)> `/study-buddy.json` > 默认值**,
逐键合并;四层都没有 → 挂载 fail-loud 并列出给法;挂载日志回显 `vaultRoot ← 来源`。
用户级 JSON 的未知键与损坏只告警不阻断。
3. **宿主接触面收成一个模块(新增 `src/host.ts`)**:`HOST_CONTRACTS` 契约表(5 个接触点,含平台
`文件:行号` 与"变了会怎样")+ 能力探测/降级;`tools.register` 是唯一 fail-loud 点。可选探测
dsh-loader 稳定入口(不 import、不 inject:inject 了但用户没装会让整行永远 `pending`)。
`sessionCwdOf` / `ToolExecLike` / 会话事件读取集中到此,`opener.ts` 复用。
4. **`tools/verify-contract.mjs` 扩成两类断言**:①交付形态(`dsh.bundle.patch` 存在、声明可解析、
12 行组合 + 3 个压缩子行、`study` 行 config 键 ⊆ 插件认得的键且**不含 `vaultRoot`**、`src/` 与 `lib/`
无 `@deepseek-ai/*` 静态 import)②平台契约(含"假 ctx 不给 `settings` 也必须注册 18 个工具"的
负向断言、peer 范围用**平台自己的门禁**校验)。负向对照 6 例全覆盖。13 → 22 条断言。
5. **`tools/verify-deploy.ps1` 从"部署三要素"改为"四要素"**:产物哈希、已装 bundle 的
`dsh.bundle.patch` + patch 哈希 + patch 里不得含 `vaultRoot`、profile 的 `dsh.profile.bundles`
是否选中、legacy `.agent-presets\study` 必须已删除、技能目录与《笔记期望.md》;vaultRoot 从
环境变量/用户级 JSON 解析。
6. **测试**:新增 `tests/config.spec.ts`(12 项,注入 env/readFile 的来源链单测);`tests/preset.spec.ts`
重写为声明卫生(8 项,含"目录式预设必须已退场"与"不含 vaultRoot");`tests/apply.spec.ts` 加来源链
集成(15 项)。测试 276 → 292 项,模块 21 → 23。
7. **文档**:README 增「安装与兼容性」(版本矩阵 / peer 门禁 / dsh-loader 的边界);用户指南 §3 安装部署
全部改写(bundle 选中 + 三选一给 vaultRoot)、§4 配置来源表、§11.2 四要素自查;技术文档新增 §9.2
「交付形态:声明式预设」;设计文档 D25/D26 记录两个决策与取舍。
## v1.0.2 — 归档链路修复(真机检查报告;随 v1.1.0 一起发布)
起因:[`docs/check/验证报告-2026-09-15-学习伙伴预设实战检查.md`](check/验证报告-2026-09-15-学习伙伴预设实战检查.md) 在真机会话逐条跑 50 项,
暴露 **P0:`note_plan` 没有确认入口**——`buildPlanRecord` 写死 `confirmed: false`,却没有任何调用点能置位,
于是 `note_write` 在任何会话都必然被"规划尚未确认"拦下(报错文案里的 `note_plan(action=confirm)` 是一条不存在的逃生口)。
逐条修复见 [`check/验证报告-2026-09-15-归档链路修复复验.md`](check/验证报告-2026-09-15-归档链路修复复验.md)。
1. **P0 · `note_plan` 补 `confirm`(`src/index.ts` / `src/tools.ts`)**:`action` 枚举加 `confirm`(`confirm`/`abandon` 都从 `rootPath` 取 planId,
schema 必填集合不随动作漂移)。确认时置 `confirmed` + `confirmedAt`、接管 `activePlanId`;**有效期从确认时刻重新起算**
(搁置超期的提案仍要求重新提案,拒绝时磁盘零改动)。`gate.ts` / `planstore.ts` 的拒绝文案改为**就本次 planId 给出可执行的调用式**。
2. **P0 · 测试不再绕过那一步**:`tests/noteflow.spec.ts` 的 `planAndConfirm` 删掉"手改 `.study/plans/*.json` 置位 `confirmed`"的写法
(正是它让"点不出已确认的规划"与全绿同时成立),改走真实 `confirm`;补 4 项端到端用例(确认链路、幂等、三类非法 planId、过期/重算)。
3. **P0′ · 新查出 `generatePlanId` 补零死锁(`src/planstore.ts`)**:小时位没补零使 id 在 00:00~09:59 只有 11 位,
而 `planFileFor` 要求恰好 12 位——**凭据刚发出去就被自己的校验拒绝**。改为所有两位字段统一补零,并用"刚生成的 id 必须能换回路径"钉住。
4. **P2 · 简介与正文首句去重(`src/note.ts`)**:`renderNote` 在未显式传 `summary` 时把正文首个引用块**同时**写进 `简介` 与正文首行
(《笔记期望.md》要求的"术语首现给定义"正好触发)。改为只有显式 `summary` 才前置引用块,缺省时由正文那一行充当定位。
5. **P1 · 批量体检去掉均分(`src/lint.ts`)**:`LintBatch.average` 与"平均问题数:N 条"一并删除——100 分制已退场,
"问题数的平均"同属残留口径;报告只给"有问题的文档数 + 问题数分布 + 规则命中 + 问题最多的文档"。
6. **P1 · 验证清单订正(`docs/check/prompt-verify-all-features.md`)**:第 12 项改为"判定标准是被拒 + 磁盘零改动,不要求命中具体文案"
(门禁按序短路,一次只说一个问题);补 `confirm` 步骤(18b)与简介去重检查(36b);修 `newTitle`→`title`、`note_restore` 是独立工具、
第 20 项改用"规划内另一个路径"才能命中消费记账;收尾补 `.study/plans/` 清理项。
7. **预设侧同步**:persona 归档硬门禁第 2 条与工具行、`note-format` / `study-loop` 技能都写明"拍板后还要 `confirm`",并加测试钉住。
8. **文档**:`设计文档.md` §3 补确认入口与"确认时重新起算"的取舍、D7 更新;`技术文档.md` §2.7/§3/§3.1/§5/§8 同步;`用户使用指南.md` §6.6/§7/§7.7/§11 同步。
测试 271 → 276 项。
## v1.0.1(2026-09-15)— DSH 更新适配与契约校验
起因:按 DSH 升级手册排查「DSH 更新后插件失效」。结论是**平台侧没有打断本插件**,但暴露出
一类以前没被钉住的退化形态。
1. **平台侧核对(逐条,无改动)**:本次更新的破坏性提交 `e459e32637`(Typert strict codec 的
`schema` → `create()`)与 `42286726c8` / `eb8cc594b3` / `232ab768a9` 对本插件**不适用**——`build.mjs`
把 `@deepseek-ai/*` 全部 external,产物只有 `node:` 导入。逐点复核了 `tools.register(ToolDefinition)`、
`Session.snapshotEvents()`、`agent/pre-step` 载荷、`session.header.cwd`、`systemPrompt.section()`:
形状一致;`Session.events` 的移除早在 `opener.ts` 里做了双形状探测(旧分支如今恒为 `undefined`,
由 `snapshotEvents()` 兜住)。
2. **新增 `tools/verify-contract.mjs`(`pnpm run verify:contract`)**:把上述 5 个契约点变成可执行断言,
并把 `lib/` 的产物形状(18 个工具名、`output` 契约、apply 接线与可逆性)一起钉住;能从
`$DSH_HOME/profiles/*/node_modules` 解析到平台包时,直接 import 真的 `ToolRuntime` / `Session` /
`SystemPrompt` 断言方法仍在(解析不到则跳过,CI 不会因此变红)。`--self-test` 跑负向对照:
把断言改坏必须报错。**这个性质当场抓出一个洞**——最初的 `check()` 把"回调返回字符串"当通过,
于是"读到不对 → 返回中文诊断"的分支把自己的诊断算成了绿灯。
3. **新增 `tools/verify-deploy.ps1`(`pnpm run verify:deploy -- -Profile web`)**:只读比对
仓库产物哈希 ↔ profile 安装副本、部署预设 ↔ 仓库模板(行/键集合/技能目录,`vaultRoot` 允许不同)、
vault 的《笔记期望.md》与 `.dsh-module-fallback` 污染。`file:` 依赖不自动刷新 + 预设是各机自编副本,
这两处是"看着改了其实没生效"的常客。
4. **插件侧新增配置键漂移告警**:`apply()` 遇到不认识的 config 键(已退场键或拼写错误)会点名打印,
但**不抛错**(抛错会把一个能跑的行挂掉)。这条正对本轮查出的真实退化:部署副本里留着 `mocDir`。
5. **测试**:新增 `tests/contract.spec.ts`(9 项,仓库自测侧的宿主契约);`tests/apply.spec.ts` 补 3 项
告警用例;清掉 4 处测试里残留的 `mocDir`(`VaultLayout` 里本就没这个键,是死数据)。259 → 271 项。
6. **文档**:用户指南 §11.1 补"工具在但模型调 `card_*`"这一症状与处理、§11.2 部署自查改成可用命令判、
§3.7 写明"预设只有两处该与本机不同";新增 [`tools/README.md`](../tools/README.md)(两条命令的分工与判读)
与 [`docs/check/升级后验收清单.md`](check/升级后验收清单.md)(重启后怎么算验收通过)。
7. **未做**:不给 `package.json` 加 `dsh.bundle`(那会把 18 个工具推到宿主平面、对所有 agent 全局可见,
`cordis.patch.yml` 只作备用);`cordis.patch.yml` / `dsh.plugin.json` 保留(查询确认当前 DSH 工作树内
没有读取方,属生态惯例文件,不再是契约点)。
## v1.0.0(2026-10-24)— 文档式笔记重构
从"原子卡片"转向"文档式笔记"。
1. **过程文档**:需求分析(26 问落成 30 条决策)→ 架构选型 → 8 阶段重构计划,三份见 [`docs/refactor/`](refactor/)。
2. **解除约束**:删除三型模板 / 必填小节 / 分型推断 / `定义 ≤60 字`硬拒绝 / 14 条 lint 打分(改为 4 条数据卫生规则、无分值);写法唯一来源改为用户自己的《笔记期望.md》(缺失时 fail-loud,不回退到内建写法)。
3. **目录约束**:新建 `note_plan`(提案只在对话里 + 用户确认)、`note_toc`(微目录,手写导读保留)、`note_overview`(按 `来源章节` 的覆盖度,不虚构章节)。
4. **硬门禁**:`note_write` 三连校验(期望已读签名一致 / 规划已确认未过期 / 路径在规划内),拒绝时**磁盘零改动**。
5. **历史存档**:`replace` / `restore` 走 `archiveThenWrite`(先存档后写正文),正文不留 ``;新增 `note_history` / `note_restore`。
6. **关联改 wikilink**,新增 `note_unlink`;`note_rename` 同步 frontmatter + 文件名 + 全库入链。
7. **工具面重建**:12 个 `card_*` / `study_*` → 18 个 `note_*` / `study_*`(一个工具一个动词);`card_moc` / `card_id` 删除。
8. **架构**:模块 16 → 21(新增 `dirs` / `gate` / `planstore` / `archive` / `store` / `overview` / `sourceSection` / `order`;删除 `template` / `insight` / `card` / `moc` / `history` / `updatelegacy`;`rename` 并入 `links`);**索引不再常驻正文**;构建前清 `lib/types`。
9. **预设侧**:persona 重写、`card-format` → `note-format`、`domain-adaptation` 去掉自带侧重表(改为引导写进期望)、新增默认期望模板 `presets/study/assets/笔记期望.md`、配置键删 `mocDir` / `templateHints` 加 `expectFile` / `planTtlHours`。
10. **排序口径固定**:全部文本排序收成 `src/order.ts`(显式 `zh-Hans-CN` + 数字按数值),不再随宿主 locale 变化——裸 `localeCompare` 会让同一 vault 在不同机器上列出不同顺序,CI 在 en-US 上暴露过一次顺序翻转。
11. **文档整理**:本轮过程文档移入 `docs/refactor/`,v0.9 审查台账移入 `docs/archive/`,新增本文件(其余现行文档仍在 `docs/` 根目录,地图见 [`docs/README.md`](README.md))。
测试 268 → 252(删掉的是被删功能的用例,安全类一条未删)。需求与选型见 [`需求分析.md`](refactor/需求分析.md)、[`架构选型.md`](refactor/架构选型.md)、[`重构计划.md`](refactor/重构计划.md)。
## v0.9.1(2026-09-10)— 复审(`docs/archive/review/07`)N1~N15 修复
① `card_link` 一侧位于只读检索根时**先校验后写盘**(旧实现先写 A 再在 B 处报错,留下单向入链)——改为两侧全部规划完再落盘,中途失败按写前内容回滚;② `card_create` 不再为同名提示触发全库重扫(改 `titleHints` O(1) 查询);③ 索引 TTL 的可见性回归修复:**未命中/找不到卡片的路径强制重扫一次**;④ 其余 12 项 nit。另新增 `tests/docs.spec.ts`(文档链接/锚点 + 版本基线守卫)与 `docs/README.md`(文档地图)。测试 248 → 263;逐条状态见 [`审查修复记录.md`](archive/审查修复记录.md) §三。
## v0.9.0(2026-09-10)— 首轮审查修复
明细归档于 `docs/archive/review/`。3 个 blocker(`strip` 行号漂移删错正文、换行截断 frontmatter、`rename` 半写盘)+ 15 warning + 12 nit;lint 收敛为 `RULES` 注册表;索引 TTL;工具仍 12 个,测试 209 → 248。
## v0.8.0(2026-09-10)— P1/P2 收口
模板分型与四个新小节落进代码与文档;`card_lint` 增 `cross` / `trend` / `rating` 三个分析开关。测试 203 → 209。
## v0.6.0(2026-09-10)— 卡片质量可检测
新增 `card_lint`(14 条规则)、`card_history`、`card_rename`;会话残留白名单;工具 9 → 12,测试 136 → 201。
## v0.5.0(2026-09-07)— dsh 0.1.3-alpha.1 平台适配
宿主侧仍零 `@deepseek-ai` 运行时导入;开场门禁改为**双形状特性探测**(兼容 `session.events` 与 `session.snapshotEvents()`)。
## v0.4.0(2026-09-03)
自迭代记忆开关、开场记忆硬门禁、课件图片提取;多根检索与旧笔记联动。
## v0.3.0(2026-08-21)
记忆功能;修复 vaultRoot == cwd 时工具静默不注册(改为 fail-loud)。