DeepSeek Harness 共享包契约回归:deepEqualJson 与 marketVersion 排查
这五个问题都不是「用错 API」,而是共享包的行为与它自己声明的契约对不上,所以升级版本不会自动消失。 有用户在 687f282e86 上逐条只读复核,结论是 5/5 都是真实缺陷;补丁与回归测试在 fork 分支上,尚未合并进官方仓库(Discussion #10065)。
DeepSeek Harness 共享包五个缺陷分别错在哪、影响谁
共同点是「校验或比较的实现比文档窄」,每一处都能用一段最小输入打出来。 逐条对照:
values的deepEqualJson用in加成员读取比较记录。预期判据:{"__proto__":{},"b":2}与{"a":1,"b":2}被判相等,因为继承成员满足了左侧的a。修法是只比较自有属性。plugin-market-index的marketVersion只用 SemVer 语法正则。预期判据:超长版本号能通过校验,但列表排序走semver.rcompare时抛裸TypeError,而不是MarketIndexError。values的PartialArguments#invalid读取时不经过remember。预期判据:读完之后才发现的无效状态不会触发refresh(),与complete()的行为不一致。llm的normalizeLlmFailure渲染非Error抛出。预期判据:抛{message, code}时错误信息变成[object Object],原始 message 丢失。llm的boundContextSummary按码元截断。预期判据:切点落在代理对内部时,摘要里留下孤立的高位代理项,并随消息进入持久化日志。
补丁分支同时纠正了两处文档:code-language 的 JSDoc 把 hcl 写成映射到 tf,而实际表里 hcl 仍映射 hcl;plugin-market-index 的 README 声称无运行时依赖,实际校验器依赖 semver 与包清单包。据讨论,复核者认为后一条的描述比代码多算了一个包。
五处缺陷的触发面完全不同,按输入特征分流比一次性全改更稳。 四步:
- 检查你的 JSON 输入里是否可能出现
__proto__、constructor这类键。预期结果:只有这类输入会踩deepEqualJson,普通对象比较不受影响。 - 检查市场索引里是否存在超长或格式边缘的版本号。预期结果:正常 SemVer 不会触发
marketVersion的排序异常。 - 检查你是否依赖
PartialArguments#invalid变化后的回调。预期结果:不读这个字段的调用方完全碰不到第三处。 - 在日志里搜
[object Object]与替换字符。预期结果:出现前者说明踩了非Error抛出,出现后者要看摘要截断。
分流的价值在于:多数应用只会踩一到两处,把五处全改反而扩大了回归面。
DSH插件路径一:合入补丁分支
适合能改宿主源码、并且要一次性解决全部五处的人。 做法:
- 拉取 fork 分支
fix/shared-contract-regressions-20261017。预期结果:能看到五个独立提交,分别对应上面的五个缺陷。 - 对照提交说明挑出你需要的部分,逐个 cherry-pick 到自己的基线。预期结果:每个提交只动一个包,冲突范围可控。
- 跑对应包的测试与受影响消费者的测试。预期结果:新增回归用例在未修源码上失败、在修后通过。
- 记录基线 commit 与 cherry-pick 顺序。预期结果:下次升级宿主时能判断这些补丁是否已被官方吸收。
五个提交分别是 fc74097e0e(deepEqualJson)、038c710d33(marketVersion)、b49f975945(invalid 观察)、d451d26f9b(非 Error 抛出)、61ee3f668e(代理对截断),据讨论均带回归测试。
DeepSeek Harness 路径二:逐个包打局部补丁
适合不想整体替换宿主、只想修自己实际踩到的那一两个包的人。 步骤:
- 先确定哪个包真的影响了你的功能,不要五个一起改。预期结果:列出一到两个包名与触发场景。
- 在本地用你现有的 patch 机制覆盖该包的构建产物,只改比较或校验那一小段。预期结果:包版本号不变,行为按预期变化。
- 为每处改动补一个最小用例,输入就用上面判据里的那段 JSON 或版本号。预期结果:不打补丁时用例失败,打上后通过。
- 在升级宿主后重新应用并重跑用例。预期结果:补丁未失效,或已被上游修复从而可以删除。
局部补丁的代价是升级时要重新核对偏移,尤其是压缩产物里的行号会变。用行为断言而不是行号定位,能省掉很多返工。
DeepSeek Harness 路径三:在调用侧加防御
适合完全不能改依赖、只需要让自己的插件不出错的人;在 DSH Plugin Hub 发布插件前,也建议先确认自己不会被这些共享包行为拖垮。 三处最常见的防御:
- 比较 JSON 前先做一次自有属性归一,比如只取
Object.keys能枚举到的键再比较。预期结果:原型链上的成员不再影响相等判断。 - 使用
marketVersion的返回值前,自己再跑一次semver.valid并限制长度。预期结果:超长版本号在进入排序前就被拒绝,不会抛裸TypeError。 - 捕获非
Error抛出时,先判断对象上有没有自有的message字符串,再回退到String(value)。预期结果:日志里不再出现[object Object]。
调用侧防御不会修好共享包,别的调用方仍然会踩。它的价值是把故障限制在你自己的边界内,给你时间等上游合并。
DeepSeek Harness 用回归测试确认补丁真的生效
只看代码 diff 不够,五处都需要一个能独立失败的最小输入。 按顺序建测试:
- 为
deepEqualJson写一条含__proto__键的相等断言。预期结果:未修时断言通过(错误地相等),修后断言失败(正确地不等)。 - 为
marketVersion写一条超长版本号用例,断言抛出的是MarketIndexError。预期结果:未修时收到TypeError。 - 为
PartialArguments#invalid写「先读 invalid、再改内容、检查 refresh 次数」的用例。预期结果:未修时 refresh 不触发。 - 为非
Error抛出与代理对截断各写一条字符串断言。预期结果:前者不再包含[object Object],后者不再出现孤立代理项。
这组用例的写法是「在当前源码上必须失败」,否则它没有守住任何东西。
DeepSeek Harness 处理这类契约缺陷的注意事项
先分清「文档写错」与「实现写错」,两者的修法不同。 四点:
- 文档强于代码时,优先修文档还是修代码取决于调用方是否已经依赖文档语义。已经有人按文档写调用时,应修代码。
- 共享包的修复要连带跑消费者的测试,
values与llm的改动面比看起来大。 - 外部 PR 不被接受时,fork 分支加讨论帖是目前可行的提交方式,别把补丁只留在本地。
- 升级宿主后重新核对这些提交是否已被吸收,避免同一段逻辑被改两遍。
据讨论,这五处目前都还没有进官方版本,属于「补丁可用、待合入」的状态。把它们当成已知边界写进你的兼容说明,比等一个不确定的修复时间更实际。
三条路的适用范围可以这样分:
- 合入补丁分支:一次改五个包,升级时要重解冲突,适合能改宿主源码的人。
- 逐包打局部补丁:只改踩到的一两个包,代价是每次升级都要重新核对产物偏移。
- 调用侧防御:完全不动依赖,代价是防御逻辑得自己维护,别处调用方仍然会踩。
三条不互斥:先做调用侧防御止血,再挑需要的提交 cherry-pick,是常见顺序。 如果团队同时维护多个宿主分支,给每个分支记录一份「已合入哪几条」的清单,避免升级时把已验证的补丁又解一遍。
来源:Discussion #10065、fix/shared-contract-regressions-20261017。更多插件侧排查入口见 DSH 故障排查。
常见问题
DeepSeek Harness 的旧实现用 in 加成员读取来比较记录,继承自 Object.prototype 的成员也能满足左侧键,于是 {"__proto__":{},"b":2} 会与 {"a":1,"b":2} 相等。修法是只比较自有属性,补丁分支里的提交是 fc74097e0e。
DeepSeek Harness 会放过超长版本号,并让排序在遇到它时抛出裸 TypeError,而不是文档承诺的 MarketIndexError。原因是正则只管语法,真正排序走 semver.rcompare,后者还会限制总长度与每个数字标识符,补丁改为用 node-semver 一起校验。
DeepSeek Harness 的 normalizeLlmFailure 把抛出的 {message, code} 当普通对象渲染成了字符串。补丁改为读取自有且 data-backed 的 message 字段、不触发访问器,同时把 code 保持为 UNKNOWN,因为第三方错误码不属于 harness 的分类体系。
DeepSeek Harness 会在进入持久化日志的摘要里留下一个孤立的高位代理项,显示为乱码或替换字符,后续按码点处理的逻辑也可能错位。修法是在切点落在代理对内部时丢掉未配对的那一半。
相关术语
- deepEqualJson
- deepEqualJson 是 values 包里按 JSON 语义比较两个值的函数,正确实现只应比较对象的自有属性,不应让原型链上的成员参与相等判断。— https://github.com/deepseek-ai/deepseek-harness/discussions/10065
- marketVersion
- marketVersion 是 plugin-market-index 用来校验市场索引版本号的函数,它需要同时满足 SemVer 语法与排序实现的可接受范围。— https://github.com/deepseek-ai/deepseek-harness/discussions/10065
- PartialArguments#invalid
- PartialArguments#invalid 是 values 包里表示流式参数是否已判定无效的只读答案,读取它应当像 complete() 一样登记观察,否则后续的 invalid 变化不会触发 refresh。— https://github.com/deepseek-ai/deepseek-harness/discussions/10065
- surrogate pair(代理对)
- surrogate pair 是 UTF-16 中用两个 16 位码元表示一个补充平面字符的编码方式,按码元下标截断时必须避免只保留其中一半。— https://github.com/deepseek-ai/deepseek-harness/discussions/10065
来源
- deepseek-harness Discussion #10065:Five verified shared-package fixes on a fork branch· deepseek-ai(GitHub Discussions)
- 补丁分支 atharvaHJoshi/deepseek-harness @ fix/shared-contract-regressions-20261017· GitHub(atharvaHJoshi)