判断一个插件在某个 harness 版本上还能不能用
把一个插件单独放进一棵最小的 Cordis 树里启动——这是 Simulink 对封装模块的老办法;能照搬是因为 Cordis 本身就支持只启动一小块,判定也出自它自己的启动审计。所以换哪个插件、换哪两版都照跑,不需要内置任何版本清单。
判定全部来自启动审计。你的职责是运行命令、读取输出、如实转述。⛔ 不要自行推断结论,也不要改写官方的措辞。
⛔ 「不要自行推断结论」是不要替引擎下判断,不是不许质疑本工具。 装置也会产生红灯,而且长得和真故障一模一样。这份 skill 最该被质疑的地方,恰恰是它的装置。
⛔ 默认只读:诊断阶段不修改插件源码、不修改依赖、不修改 ~/.dsh,任何情况下都不修改被测的 DSH 目录。用户明确要求修复时才修,改动方案与影响面要完整写进报告,并用同一条命令在新旧两版各复跑一次作为证据。
用法不在这里,在命令自己身上
⛔ 本文不复述任何参数。 每条命令 --help 会印出它的全部参数、可照抄的示例,以及四档退出码的完整措辞——那些由代码生成,不会和实现漂开。本文只讲怎么读它给你的结果。
| 命令 | 它回答什么 |
|---|---|
manifest.js |
插件声明的 SDK 包,在这一版还在不在 |
talk.js |
挂上去跑一轮对话,起不起得来、走不走得完 |
slice.js |
插件自带的那层配置,单独起/按实际叠法起,起不起得来 |
provider.js |
谁提供这个服务/这个包这一版还在吗、它要什么、它导出什么 |
flow.js |
单个包隔离启动,记录它对每个服务做了什么 |
survey.js/closure.js/bundles.js |
全量盘点:逐包能否独立激活、最小可启动包集、官方条目索引 |
matrix/run.js |
同一份会话产物,新旧版本能否互相读取 |
⚠️ 这八条是本工具目前的内部分工,不是你必须走的八步。多数任务只用到前四条。
退出码四档,0 之外还有一个「绿但不算数」
每条命令都要看退出码,不能只看屏幕上那几行。 完整措辞由 --help 印出,这里只讲怎么用:
1是被测对象被判定为失败——照抄它点名的条目与服务。2是没能给出答案:引擎路径错、参数错,或本工具自己出错、或本工具的组合缺了东西。⛔ 这不是关于插件的结论。3是跑起来了、什么都没失败,但结论不完整。⛔ 不许表述为「通过」,命令那几行会写清还缺什么。
⭐ 1 与 2 的分工是这套工具的地基。看到 2,先看命令本身和本工具,别写进关于插件的报告。
⭐⭐ 失败有四种形状,绿灯只覆盖第一种
一件事有几种失败方式,判词就得有几档;少一档,那一档就会伪装成成功。 这是本文最该记住的一节。
- 起不来 —— 启动审计拒绝整棵树,点名是哪个条目、在等什么。这是唯一一种一眼看得见的。
- 起来了,但回调在等 —— 某个条目已报 ACTIVE,而它内部用
ctx.inject([...], cb)建的作用域还在等一个没人提供的服务。启动审计只审条目,看不见条目底下的作用域,所以屏幕上的绿灯是真的,覆盖面却是缺的:那段回调不执行,它要注册的东西一样都不在。 ⭐ 这一档同时是下一个版本会不会坏的预告——一旦上游把该依赖从作用域注入提升为条目级inject,整棵树立刻起不来。 - 回调执行了,但抛了异常 —— 基座接住它、写进日志,条目照样报 ACTIVE、条目数照样对。这是最像成功的一种失败:一个
apply整段炸掉、什么都没注册成的插件,输出曾经与成功那次逐字相同。看到⛔ 出错那几行,绿灯就不覆盖抛异常的那一段。 - 装载阶段就死 —— 一个包删掉某个具名导出,所有
import它的模块在装载时直接抛,那时还轮不到任何服务。报错形如does not provide an export named '<名字>'。
判据是两版之差,不是单版的绝对值
问「新版本有没有影响它」时:两个版本的退出码、等待项、未覆盖项完全相同 ⇒ 没有跨版本差异,这本身就是一个合法且完整的结论,即使那个退出码是 3。
⚠️ 同一条判据的反面同样有用:被测插件往 stderr 喊的话,两版逐字相同 ⇒ 是隔离环境的副作用,不是跨版本差异(它抱怨找不到 profile、找不到配置,多半属于这类)。只在一版出现才值得追。
⛔ 「3 不算通过」是回归验收的规矩,别把它压到跨版本比较上——有些 3 原理上消不掉(比如插件的浏览器侧部分),那时会把结论卡死。
⭐ 对照组:先把被测对象拿掉跑一次
按实际叠法起的时候,必须先跑一次不带被测插件的对照组,只铺底座。
对照组的合格线是「起得来」,不是「退出码 0」。 引擎自带的组件本来就有几处作用域在等,那是它们的设计,不是故障。⛔ 合格线一律写成「相对基线的变化」,不能写成一个绝对数字——这个错犯过两次,两次都把正确结论报成了错的。
叠上去之后要比的是相对对照组多了什么:条目数应当等于对照组加上你这层插入的行数;等待项应当与对照组逐字相同,多出来的才是你这层带来的;出现对照组没有的报错,才是你这层的问题。
一层不是一棵树
一份 cordis.patch.yml 是一层配置,不是一棵完整的树——按上游的定义,bundle 发布的就是配置层,profile 把它列出的各层按顺序叠到一个空的条目表上。一份补丁点名别的包是规范内的用法,插件全家桶就是这么做的。
于是两种起法答的不是同一件事,⛔ 往往不可兼得:
| 怎么起 | 答什么 | 特有的发现 |
|---|---|---|
| 单独起 | 这一层自己带齐了什么、靠别人提供什么 | 缺提供者 |
| 叠着起 | 它按用户实际的叠法起不起得来 | 撞名(把别人已经带进来的东西又带一遍) |
自带得越全越容易撞。按上游的定义,叠加层该追求的是后者——单独起红、叠着起绿,是一个健康的叠加层,不算失败。
⭐ 一层薄薄的叠加层单独起必然红,那种红没有信息量;但「两版红得不一样」永远有信息量。 别把前一句用到后一种情况上。
⚠️ 撞的是服务名与工具名,不是条目 id——给自己的行加前缀躲得开 id 冲突,躲不开这个。
⚠️ 只要有一行 import 失败,整层就整体抛错,撞名检查根本轮不到。这时两种起法的输出会逐字相同,⛔ 别读成「没有撞名」,那是「没测到」。
⭐ 两种方向相反的破坏,各看一行
「上一版能起、这一版起不来」的成因,绝大多数落在这两行之一,而它们互相看不见对方。
- 「它要什么」变了 —— 条目级
inject多了一项。⛔ 导出的函数一个没变,所以比对导出接口看不出来。 - 「它导出啥」少了 —— 删掉一个具名导出,
import它的模块在装载阶段就死。⛔ 那时还轮不到任何服务,所以「它要什么」那一行完全看不出来。
⭐⭐ 「修好这一个之后还有没有第二个」不用靠重跑撞出来。 装载失败一次只报第一个缺失绑定,所以逐个改、逐次重跑是最贵的走法。插件要哪些名字读它自己就有,引擎给哪些名字读一次就有,相减即可——第一条命令(manifest.js)会把这个插件从 SDK 取的全部具名符号一次列全,并标明哪些在这一版没了。⛔ 它印的是全集,不是「第一个」。
⛔ 别用文件搜索代替命令,也别停在「没了」 ——搬家常常连名字一起改,拿同一个名字再搜是找不到的。源码检出的包目录是分层的,按包名直接找会找不到,从而得出「这一版删了它」的错误结论;npm 安装目录的布局又是另一套。
⛔ 贯穿全程:每个红灯先问「这是被测对象,还是这套装置」
判定来自引擎自己的启动审计,但引擎看见的是我们搭给它的那个环境。看到任何红灯,先过这三问:
- 两个版本是不是同一种形态?(一个源码检出、一个 npm 安装,包集本来就不同)
- 报错里点名的文件/包,是被测插件的,还是本工具或引擎自己的?
- 对照组跑了吗?把被测对象拿掉,剩下的部分自己是绿的吗?
⭐ 装置会认领两种自己的缺口,都由命令自己印出来,不需要你去推:
- 挂在本工具的对话组合里跑,而组合缺了插件要的服务 → 点名提供者、给出补上它的命令,退
2(没能给出答案),⛔ 不是1。 - 一层单独起,而红的原因全是「别人该提供的服务这里没有」 → 点名提供者,退
3(未判定),并给出按实际叠法再跑一次的命令。叠加层单独起本来就会红,那不是对插件的判定。
它只认得出「引擎里有提供者,而这次的树里没挂」这一种,其余仍要你自己判。
⚠️ 装载失败、撞名这类不是缺提供者的红,仍然是 1,那是真判定。
⭐ 比两台引擎:按「会不会让插件起不来」分档读
survey.js 把一份引擎的全部契约采下来(每个包要什么、给什么、官方把它挂在哪个 id 下),--against 拿它和另一份比。读法只有一条:看档,不看条数。
| 档 | 里面是什么 | 怎么读 |
|---|---|---|
| 会让插件起不来 | 包没了/具名导出少了/条目级 inject 多了一项 |
每一条都是某个插件的硬故障 |
| 可能有影响 | 条目 id 变了(撞名的形状跟着变)/config 变了(有些插件不给配置会自我禁用) | 要结合那个插件自己的写法判断 |
| 判不了 | 两份快照形态不同时的「包在不在」/某个包这一版没起来所以没测到它提供什么 | ⛔ 这一档不是结论,别当成发现 |
| 不会让插件起不来 | 新增的包、新增的导出、不再要求的依赖 | 记录,不排队 |
⭐ 加 --plugin 把这个比较投影到某个插件的接触面上(它 import 的那些名字、它声明的依赖)。引擎级几十条落到单个插件头上通常只剩一两条——那一两条才是它要改的东西。全量和单插件是同一个计算的两个视图,不是两件事。
量程边界(都要写进报告)
- ⛔ 浏览器侧一行都测不到。
manifest.js会自己认领这一条:它本来就在解析那份package.json,所以有没有浏览器侧由它印出来(dsh.client.inject/dsh.client.platform/exports里的./client,并说明是哪个信号触发的),⛔ 不用你去翻文件。有的话,从那一刻起所有结论只适用于主机侧。⚠️ 这类插件等的是connection/webRuntime/clientModules这类通道时,记为「未覆盖」然后停手——⛔ 别继续往树里补提供者,补进去的自己又会等别的,永远追不完。 - ⛔ 看不见用户实际的 profile。 能证明「和官方底座撞了」,不能证明「和用户的机器不撞」。报结论必须写明你是按哪几个 bundle 叠的。
- ⛔ 跨形态比较两个方向都会错。 装机版报某个名字缺失,可能只是没被装进来,⛔ 不等于这一版删了它;源码检出报「都在」,⛔ 不等于用户装得到。命令会自报本次是哪种形态。
- ⛔ 不发网络请求。 某个版本在 npm 上有没有、发了哪些包,本工具答不了,要你自己查。
- 可加载不等于功能正确。 插件内部的逻辑错误不在覆盖范围内。
五个常见误判
- 两个版本都通过时,先确认测的是不是插件真正发布的那棵树——最容易出错的一处:插件自带的组合没跑,而本工具的组合替它补上了缺口。
- 两个版本都失败时先排查本工具的组合,而非插件。
- 未剔除插件自带的
@deepseek-ai副本 → 测的是插件自带的 SDK 版本,不是被测引擎。 - 只看屏幕不看退出码 → 绿色的三行下面可能跟着「本次没测到你自带的组合」。
- 把盘点读成判定:引擎自己就有几十个包不能单独启动(抽象接缝、纯 bundle),全量扫描里的
refused属正常。
报告格式
- 结论:一句话,含版本号与判定来源(例:「在 <版本> 上,启动审计报告它等待服务 X」)
- 证据:命令、原始输出与退出码,⛔ 不改写措辞
- 未覆盖部分:浏览器侧、条件分支中的调用、功能正确性
- 建议:指出需要进一步核查的位置,⛔ 不代替用户决定如何修改
配置纪律
- 官方包那几行的配置一律取自官方 bundle,命令会替你抄。⛔ 自己编配置,报出来的会是我们的配置错误,而不是被测对象的问题。
- 被测插件自己那一行的配置由插件作者提供。 有些插件不给配置会自我禁用,这时缺的不是官方配置,要向用户要。
参考
references/method.md —— 隔离测试的原理、判定纪律、依赖的官方接口。