dsh-standards 1.3.0 → 1.4.0
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.
- package/40-checker/scripts/build-sidecar.mjs +238 -8
- package/40-checker/src/author-cli.mjs +274 -7
- package/40-checker/src/author-report.mjs +14 -3
- package/40-checker/src/bundle-static.mjs +181 -0
- package/40-checker/src/cli.mjs +27 -3
- package/40-checker/src/client-shape.mjs +33 -3
- package/40-checker/src/declarations.mjs +53 -8
- package/40-checker/src/index.mjs +3 -1
- package/40-checker/src/manifest.mjs +87 -14
- package/40-checker/src/remediation.mjs +108 -7
- package/40-checker/src/report.mjs +83 -7
- package/40-checker/src/semver.mjs +112 -65
- package/40-checker/src/util.mjs +51 -8
- package/CHANGELOG.md +23 -0
- package/README.md +28 -16
- package/docs/coverage.md +82 -0
- package/package.json +1 -1
- package/spec/coverage-contract.md +100 -0
- package/spec/dsc-clauses.json +766 -0
- package/spec/examples/boost-card.example.json +15 -0
- package/spec/examples/flow-evidence.example.json +113 -0
- package/spec/remediation.json +54 -54
- package/spec/schemas/boost-card.schema.json +107 -0
- package/spec/schemas/conformance.schema.json +848 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"subject": "@acme/dsh-hello@0.1.0",
|
|
3
|
+
"host": "dsh 0.2.2-alpha.3 / cordis 4.0.6-alpha.2 / node 24.9 / linux-x64",
|
|
4
|
+
"method": "字段示例:单机单次;安装后启动与一轮对话,对照 nonce arm;非生产基准",
|
|
5
|
+
"scope": "LEV-6 稳定前缀/装配 — hello 示例的工具与提示声明",
|
|
6
|
+
"command": "node bench/hello.mjs",
|
|
7
|
+
"result": "startupMs 180 → 150; reloadMs 900 → 600; tokensPerTurn 1200 → 900; loc 420 → 380",
|
|
8
|
+
"negativeControl": "同一基准换 nonce arm:prefix 复用 0%,首个分歧在 system 第 0 字节",
|
|
9
|
+
"generatedAt": "2026-11-06",
|
|
10
|
+
"expiresAt": "2027-05-06",
|
|
11
|
+
"claimLevel": "self-assessed",
|
|
12
|
+
"issuer": "author",
|
|
13
|
+
"selfAssessed": true,
|
|
14
|
+
"recordHash": "sha256:355f4015eadd3610f64cb1caab35f576f374a8fb718a761cfebad419de85f644"
|
|
15
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": "dsh-flow-evidence/2",
|
|
3
|
+
"evidenceId": "01JCM8Z6R4W1V2K3N4P5Q6R7S8",
|
|
4
|
+
"generatedAt": "2026-11-06T12:00:00Z",
|
|
5
|
+
"producer": {
|
|
6
|
+
"command": [
|
|
7
|
+
"node",
|
|
8
|
+
"40-checker/bin/dsh-flow-collect.mjs",
|
|
9
|
+
"--package",
|
|
10
|
+
"."
|
|
11
|
+
],
|
|
12
|
+
"at": "2026-11-06T12:00:00Z",
|
|
13
|
+
"kind": "local",
|
|
14
|
+
"runner": "flow-collect 0.1.0",
|
|
15
|
+
"actor": "author"
|
|
16
|
+
},
|
|
17
|
+
"subject": {
|
|
18
|
+
"name": "@acme/dsh-hello",
|
|
19
|
+
"version": "0.1.0",
|
|
20
|
+
"source": "npm",
|
|
21
|
+
"integrity": "sha512-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
|
|
22
|
+
"tarballSha256": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
23
|
+
"commit": "ce7073d51254c26cd63b22a60835b8f948deb447",
|
|
24
|
+
"treeSha256": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
|
25
|
+
"treeStable": true
|
|
26
|
+
},
|
|
27
|
+
"host": {
|
|
28
|
+
"dsh": "0.2.2-alpha.2",
|
|
29
|
+
"dshCommit": null,
|
|
30
|
+
"cordis": "4.0.6-alpha.1",
|
|
31
|
+
"node": "v24.11.0",
|
|
32
|
+
"platform": "linux-x64"
|
|
33
|
+
},
|
|
34
|
+
"journeys": {
|
|
35
|
+
"J1": {
|
|
36
|
+
"status": "pass",
|
|
37
|
+
"limitations": [],
|
|
38
|
+
"checks": [
|
|
39
|
+
{
|
|
40
|
+
"id": "J1.install",
|
|
41
|
+
"kind": "observed",
|
|
42
|
+
"command": [
|
|
43
|
+
"dsh",
|
|
44
|
+
"plugin",
|
|
45
|
+
"add",
|
|
46
|
+
"."
|
|
47
|
+
],
|
|
48
|
+
"exitCode": 0,
|
|
49
|
+
"startedAt": "2026-11-06T11:00:01Z",
|
|
50
|
+
"endedAt": "2026-11-06T11:00:09Z",
|
|
51
|
+
"stdout": {
|
|
52
|
+
"path": "logs/J1.install.out",
|
|
53
|
+
"sha256": "sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
|
|
54
|
+
},
|
|
55
|
+
"assertions": [
|
|
56
|
+
{
|
|
57
|
+
"claim": "row visible in dump",
|
|
58
|
+
"observed": true
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
"durationMs": 8000
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
"J2": {
|
|
66
|
+
"status": "not-run",
|
|
67
|
+
"reason": "not collected in this example",
|
|
68
|
+
"checks": []
|
|
69
|
+
},
|
|
70
|
+
"J3": {
|
|
71
|
+
"status": "not-run",
|
|
72
|
+
"reason": "not collected in this example",
|
|
73
|
+
"checks": []
|
|
74
|
+
},
|
|
75
|
+
"J4": {
|
|
76
|
+
"status": "not-run",
|
|
77
|
+
"reason": "not collected in this example",
|
|
78
|
+
"checks": []
|
|
79
|
+
},
|
|
80
|
+
"J5": {
|
|
81
|
+
"status": "not-run",
|
|
82
|
+
"reason": "not collected in this example",
|
|
83
|
+
"checks": []
|
|
84
|
+
},
|
|
85
|
+
"J6": {
|
|
86
|
+
"status": "not-run",
|
|
87
|
+
"reason": "not collected in this example",
|
|
88
|
+
"checks": []
|
|
89
|
+
},
|
|
90
|
+
"J7": {
|
|
91
|
+
"status": "not-run",
|
|
92
|
+
"reason": "not collected in this example",
|
|
93
|
+
"checks": []
|
|
94
|
+
},
|
|
95
|
+
"J8": {
|
|
96
|
+
"status": "na",
|
|
97
|
+
"reason": "no dsh.client",
|
|
98
|
+
"checks": []
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
"claims": {
|
|
102
|
+
"claimLevel": "self-attested",
|
|
103
|
+
"notClaimed": [
|
|
104
|
+
"certification",
|
|
105
|
+
"security audit"
|
|
106
|
+
],
|
|
107
|
+
"method": "structural example: one observed J1 run; J2-J8 not collected"
|
|
108
|
+
},
|
|
109
|
+
"conclusion": "flow-warn",
|
|
110
|
+
"chain": {
|
|
111
|
+
"evidenceHash": "sha256:ee0364bfd26362dca8265c04b7609f6d489c100826c4778e46a1f9f56f3aa138"
|
|
112
|
+
}
|
|
113
|
+
}
|
package/spec/remediation.json
CHANGED
|
@@ -3,266 +3,266 @@
|
|
|
3
3
|
"title": "清单与入口可解析",
|
|
4
4
|
"why": "package.json 是宿主识别插件的唯一入口;name/version/入口缺失会让安装或加载直接失败。",
|
|
5
5
|
"fix": "确保 package.json 可 JSON 解析,声明合法 name 与精确 SemVer version,并让 exports[\".\"] 或 main 指向包内真实存在的文件。",
|
|
6
|
-
"docs": "docs/entry.md#
|
|
6
|
+
"docs": "docs/entry.md#package-shape",
|
|
7
7
|
"severityHint": "fail"
|
|
8
8
|
},
|
|
9
9
|
"C-1.1": {
|
|
10
10
|
"title": "包名与版本必须合法",
|
|
11
11
|
"why": "非法 npm 包名或 range/tag 版本无法被 registry/market 解析,也会破坏升级与回滚。",
|
|
12
12
|
"fix": "name 用 @scope/name 或小写 name;version 写精确 SemVer(如 1.2.3),不要写 latest 或 ^1.2.3。",
|
|
13
|
-
"docs": "docs/entry.md#
|
|
13
|
+
"docs": "docs/entry.md#package-shape",
|
|
14
14
|
"severityHint": "fail"
|
|
15
15
|
},
|
|
16
16
|
"C-1.2": {
|
|
17
17
|
"title": "入口必须可解析且留在包内",
|
|
18
18
|
"why": "exports/main 指向缺失或越界文件时,安装成功但加载必失败。",
|
|
19
19
|
"fix": "确认 exports[\".\"]/main 指向实际发布进包的文件;不要在 files 里漏掉该目录;路径不得用 .. 逃出包。",
|
|
20
|
-
"docs": "docs/entry.md#
|
|
20
|
+
"docs": "docs/entry.md#package-shape",
|
|
21
21
|
"severityHint": "fail"
|
|
22
22
|
},
|
|
23
23
|
"C-1.3": {
|
|
24
24
|
"title": "导出形态要符合 Loader 约定",
|
|
25
25
|
"why": "Cordis Loader 只接受函数插件的 apply 或默认导出服务类,混用会让插件无法装载。",
|
|
26
26
|
"fix": "二选一:export function apply(ctx)(可带 name/inject/Config),或 export default class ... extends Service;不要在同一入口再混一个默认导出。",
|
|
27
|
-
"docs": "docs/entry.md#
|
|
27
|
+
"docs": "docs/entry.md#package-shape",
|
|
28
28
|
"severityHint": "warn"
|
|
29
29
|
},
|
|
30
30
|
"C-1.4": {
|
|
31
31
|
"title": "bundle patch 必须在包内且可解析",
|
|
32
32
|
"why": "patch 路径越界、缺失或行 name 逃逸会让 bundle 安装后无法合成 profile。",
|
|
33
33
|
"fix": "把 patch 文件放进包内并在 dsh.bundle.patch 用相对路径声明;避免 ..、绝对路径、~、$VAR;确认每个 patch 行的 name 仍在包内。",
|
|
34
|
-
"docs": "docs/entry.md#
|
|
34
|
+
"docs": "docs/entry.md#package-shape",
|
|
35
35
|
"severityHint": "fail"
|
|
36
36
|
},
|
|
37
37
|
"C-1.5": {
|
|
38
38
|
"title": "声明 license(建议 SPDX)",
|
|
39
39
|
"why": "缺 license 是 advisory WARN,但会让市场/企业用户无法判断使用条款。",
|
|
40
40
|
"fix": "在 package.json 加 \"license\": \"Apache-2.0\"(或实际 SPDX 标识),并在 files 里带上 LICENSE。",
|
|
41
|
-
"docs": "docs/entry.md#
|
|
41
|
+
"docs": "docs/entry.md#package-shape",
|
|
42
42
|
"severityHint": "warn"
|
|
43
43
|
},
|
|
44
44
|
"C-1.6": {
|
|
45
45
|
"title": "private 包不可发布",
|
|
46
46
|
"why": "private: true 的包能被本地安装但不该出现在 registry/市场。",
|
|
47
47
|
"fix": "要发布就移除 private: true;若只是内部包,请在 README/描述里写清来源与安装方式。",
|
|
48
|
-
"docs": "docs/entry.md#
|
|
48
|
+
"docs": "docs/entry.md#package-shape",
|
|
49
49
|
"severityHint": "warn"
|
|
50
50
|
},
|
|
51
51
|
"C-2": {
|
|
52
52
|
"title": "版本约束必须声明且兼容",
|
|
53
53
|
"why": "宿主对“无声明”按兼容处理,插件会在错误版本上静默装载然后崩溃。",
|
|
54
54
|
"fix": "在 package.json 声明 engines.dsh(首选),至少声明一个 @deepseek-ai/dsh* peer 范围;范围要覆盖目标运行时。",
|
|
55
|
-
"docs": "docs/entry.md#
|
|
55
|
+
"docs": "docs/entry.md#package-shape",
|
|
56
56
|
"severityHint": "fail"
|
|
57
57
|
},
|
|
58
58
|
"C-2.1": {
|
|
59
59
|
"title": "必须声明 engines.dsh 或 dsh peer 范围",
|
|
60
60
|
"why": "两者皆无时宿主无法阻止不兼容安装;只有 peer 时是较弱的替代声明。",
|
|
61
61
|
"fix": "加 \"engines\": { \"dsh\": \">=0.2.2-0 <0.3.0\" };若只能用 peer,至少写 \"@deepseek-ai/dsh-tools\": \">=0.2.2-0 <0.3.0\",不要留空。",
|
|
62
|
-
"docs": "docs/entry.md#
|
|
62
|
+
"docs": "docs/entry.md#package-shape",
|
|
63
63
|
"severityHint": "fail"
|
|
64
64
|
},
|
|
65
65
|
"C-2.2": {
|
|
66
66
|
"title": "声明的范围必须满足当前运行时",
|
|
67
67
|
"why": "范围不覆盖 --runtime-version 时,宿主会跳过或装上一个跑不起来的插件。",
|
|
68
68
|
"fix": "把 engines.dsh/peer 范围放宽到包含目标运行时(如 >=0.2.2-0 <0.3.0),并用 --runtime-version 复跑 C-2。",
|
|
69
|
-
"docs": "docs/entry.md#
|
|
69
|
+
"docs": "docs/entry.md#package-shape",
|
|
70
70
|
"severityHint": "fail"
|
|
71
71
|
},
|
|
72
72
|
"C-2.3": {
|
|
73
73
|
"title": "不得用 workspace: 范围糊弄版本声明",
|
|
74
74
|
"why": "workspace: 是 monorepo 内部协议,registry 消费者无法解析。",
|
|
75
75
|
"fix": "发布前把 workspace:^/workspace:* 改成真实 SemVer 范围;peer 中如确需 workspace 语义,确认宿主等价规则后再发布。",
|
|
76
|
-
"docs": "docs/entry.md#
|
|
76
|
+
"docs": "docs/entry.md#package-shape",
|
|
77
77
|
"severityHint": "fail"
|
|
78
78
|
},
|
|
79
79
|
"C-2.4": {
|
|
80
80
|
"title": "engines 与 peer 结论冲突要收敛",
|
|
81
81
|
"why": "两套声明给出不同兼容结论时,用户无法判断该信哪个;宿主以 engines 单独裁决。",
|
|
82
82
|
"fix": "保留一套权威范围(优先 engines.dsh),让 peer 范围与它一致;删掉过窄/过宽的重复声明。",
|
|
83
|
-
"docs": "docs/entry.md#
|
|
83
|
+
"docs": "docs/entry.md#package-shape",
|
|
84
84
|
"severityHint": "warn"
|
|
85
85
|
},
|
|
86
86
|
"C-3": {
|
|
87
87
|
"title": "安装来源可解析、可固定、可追溯",
|
|
88
88
|
"why": "浮动 tag/branch/裸名会在下一次安装时换成另一个 commit,无法复现。",
|
|
89
89
|
"fix": "registry 用精确版本或可校验 tag;git 用 40 位 commit;tarball 用固定 URL;不要让非 registry 依赖随 HEAD 漂移。",
|
|
90
|
-
"docs": "docs/entry.md#
|
|
90
|
+
"docs": "docs/entry.md#package-shape",
|
|
91
91
|
"severityHint": "fail"
|
|
92
92
|
},
|
|
93
93
|
"C-3.1": {
|
|
94
94
|
"title": "install spec 必须能被解析",
|
|
95
95
|
"why": "CLI 把 spec 原样交给 pnpm;解析失败意味着用户按文档装不上。",
|
|
96
96
|
"fix": "用 pkg@1.2.3、github:owner/repo#<40hex>、固定 tarball URL 或包内 path;在 README 里给出可复制命令。",
|
|
97
|
-
"docs": "docs/entry.md#
|
|
97
|
+
"docs": "docs/entry.md#package-shape",
|
|
98
98
|
"severityHint": "fail"
|
|
99
99
|
},
|
|
100
100
|
"C-3.2": {
|
|
101
101
|
"title": "registry/git 来源必须钉住",
|
|
102
102
|
"why": "裸包名或浮动 branch 会随上游发布变化,破坏可追溯性。",
|
|
103
103
|
"fix": "registry 写精确版本(@scope/pkg@1.2.3)或可校验 tag;git 写 #<40 位 commit>,不要用 #main。",
|
|
104
|
-
"docs": "docs/entry.md#
|
|
104
|
+
"docs": "docs/entry.md#package-shape",
|
|
105
105
|
"severityHint": "fail"
|
|
106
106
|
},
|
|
107
107
|
"C-3.3": {
|
|
108
108
|
"title": "非 registry 依赖必须固定",
|
|
109
109
|
"why": "file:/link:/浮动 git 依赖在别人机器上解析不到或指向不同代码。",
|
|
110
110
|
"fix": "改成固定 commit 的 git URL、固定 tarball URL 或包内相对 path;workspace:/file: 发布前替换掉。",
|
|
111
|
-
"docs": "docs/
|
|
111
|
+
"docs": "docs/entry.md#package-shape",
|
|
112
112
|
"severityHint": "warn"
|
|
113
113
|
},
|
|
114
114
|
"C-3.4": {
|
|
115
115
|
"title": "安装期构建脚本要可枚举",
|
|
116
116
|
"why": "preinstall/install/postinstall/prepare 会在用户机器上执行,profile 看不到就无法审批。",
|
|
117
117
|
"fix": "尽量去掉安装期脚本,改为显式构建;必须在 README/发布说明列出脚本与 allowBuilds 需求。",
|
|
118
|
-
"docs": "docs/
|
|
118
|
+
"docs": "docs/entry.md#package-shape",
|
|
119
119
|
"severityHint": "warn"
|
|
120
120
|
},
|
|
121
121
|
"C-3.5": {
|
|
122
122
|
"title": "市场索引条目必须可解析且固定",
|
|
123
123
|
"why": "条目版本/来源/commit 不合法时,市场无法生成可复现的安装串。",
|
|
124
124
|
"fix": "用 format-1 schema:精确 SemVer、source.type=npm|git、git 40hex、engines.dsh 合法;修完用 --market-index 复跑。",
|
|
125
|
-
"docs": "docs/
|
|
125
|
+
"docs": "docs/entry.md#package-shape",
|
|
126
126
|
"severityHint": "fail"
|
|
127
127
|
},
|
|
128
128
|
"C-4": {
|
|
129
129
|
"title": "插件必须能装载并进入 ACTIVE",
|
|
130
130
|
"why": "装载抛错/停在 PENDING/超时都意味着用户装上了但跑不起来。",
|
|
131
131
|
"fix": "在隔离 Cordis Context 中用真实 --runtime 复跑;检查入口 import、inject 服务是否在目标 profile 存在、apply 是否抛错;把阻塞初始化移到 apply 内并处理失败。",
|
|
132
|
-
"docs": "docs/
|
|
132
|
+
"docs": "docs/entry.md#runtime-surface",
|
|
133
133
|
"severityHint": "fail"
|
|
134
134
|
},
|
|
135
135
|
"C-5": {
|
|
136
136
|
"title": "声明的 provide 必须真实注册",
|
|
137
137
|
"why": "provide 只是元数据,Cordis 不会自动注册;声明了却不注册会骗过依赖方。",
|
|
138
138
|
"fix": "在 apply 里用 ctx.provide(\"name\", impl)(或 Service 构造器)注册每个声明的服务;不要只写 export const provide。",
|
|
139
|
-
"docs": "docs/
|
|
139
|
+
"docs": "docs/entry.md#runtime-surface",
|
|
140
140
|
"severityHint": "fail"
|
|
141
141
|
},
|
|
142
142
|
"C-5.1": {
|
|
143
143
|
"title": "provide 声明要可枚举",
|
|
144
144
|
"why": "动态/配置生成的 provide 让检查器无法核对,依赖方也无法预期。",
|
|
145
145
|
"fix": "把 export const provide = [...] 写成静态字符串数组;若必须动态,在 README 说明并接受 WARN。",
|
|
146
|
-
"docs": "docs/
|
|
146
|
+
"docs": "docs/entry.md#runtime-surface",
|
|
147
147
|
"severityHint": "warn"
|
|
148
148
|
},
|
|
149
149
|
"C-5.2": {
|
|
150
150
|
"title": "provide 的所有权必须是本 fiber",
|
|
151
151
|
"why": "服务被别的 fiber 注册或根本没注册,卸载/重挂时会留下悬挂依赖。",
|
|
152
152
|
"fix": "用 ctx.provide/Service 在本插件 fiber 注册;不要直接写 ctx.reflect.store 或让子 fiber 代注册。",
|
|
153
|
-
"docs": "docs/
|
|
153
|
+
"docs": "docs/entry.md#runtime-surface",
|
|
154
154
|
"severityHint": "fail"
|
|
155
155
|
},
|
|
156
156
|
"C-6": {
|
|
157
157
|
"title": "注册型副作用必须由 fiber effect 承载",
|
|
158
158
|
"why": "裸定时器/监听器不进入 _disposables,卸载后仍在跑,污染宿主。",
|
|
159
159
|
"fix": "所有 timer/listener/connection/subprocess 都包进 ctx.effect(() => { ...; return dispose });不要直接写 ctx.events._hooks/reflect.store。",
|
|
160
|
-
"docs": "docs/
|
|
160
|
+
"docs": "docs/entry.md#runtime-surface",
|
|
161
161
|
"severityHint": "fail"
|
|
162
162
|
},
|
|
163
163
|
"C-6.1": {
|
|
164
164
|
"title": "不得直写 Cordis 私有注册面",
|
|
165
165
|
"why": "绕过 ctx.on/ctx.effect 的注册不会被卸载,且跨版本必坏。",
|
|
166
166
|
"fix": "改用公开 API:ctx.on、ctx.effect、ctx.provide;删除对 _hooks、reflect.store、registry._internal、_disposables 的写操作。",
|
|
167
|
-
"docs": "docs/
|
|
167
|
+
"docs": "docs/entry.md#runtime-surface",
|
|
168
168
|
"severityHint": "fail"
|
|
169
169
|
},
|
|
170
170
|
"C-6.2": {
|
|
171
171
|
"title": "注册的 effect 要能对上声明",
|
|
172
172
|
"why": "声明了 provide/on 但 effect 树里没有对应 label,说明注册是匿名的或没发生。",
|
|
173
173
|
"fix": "给 ctx.effect(fn, \"plugin.label\") 加稳定 label;确认 fiber.getEffects() 覆盖声明的服务与监听器。",
|
|
174
|
-
"docs": "docs/
|
|
174
|
+
"docs": "docs/entry.md#runtime-surface",
|
|
175
175
|
"severityHint": "warn"
|
|
176
176
|
},
|
|
177
177
|
"C-7": {
|
|
178
178
|
"title": "dispose 后可观测残留必须归零",
|
|
179
179
|
"why": "卸载不干净会让重装/热更新累积 effect、服务、监听器和 fiber。",
|
|
180
180
|
"fix": "用 ctx.effect 注册所有资源;dispose() 后断言 getEffects().length===0、服务 key 回到基线、registry.size 回到基线。",
|
|
181
|
-
"docs": "docs/
|
|
181
|
+
"docs": "docs/entry.md#runtime-surface",
|
|
182
182
|
"severityHint": "fail"
|
|
183
183
|
},
|
|
184
184
|
"C-7.1": {
|
|
185
185
|
"title": "effect 必须清空",
|
|
186
186
|
"why": "dispose 后还有 effect 说明 disposer 没执行或资源没交给 effect。",
|
|
187
187
|
"fix": "把裸 timer/listener 放进 ctx.effect 并返回清理函数;检查 disposer 是否抛错被吞掉。",
|
|
188
|
-
"docs": "docs/
|
|
188
|
+
"docs": "docs/entry.md#runtime-surface",
|
|
189
189
|
"severityHint": "fail"
|
|
190
190
|
},
|
|
191
191
|
"C-7.2": {
|
|
192
192
|
"title": "服务 store 要回到基线",
|
|
193
193
|
"why": "残留的 provide 会让后续插件拿到已卸载的实现。",
|
|
194
194
|
"fix": "用 ctx.provide/Service 的 disposer 注销;不要手工往 reflect.store 写,卸载后对比 key 集。",
|
|
195
|
-
"docs": "docs/
|
|
195
|
+
"docs": "docs/entry.md#runtime-surface",
|
|
196
196
|
"severityHint": "fail"
|
|
197
197
|
},
|
|
198
198
|
"C-7.3": {
|
|
199
199
|
"title": "registry/fiber 不得残留",
|
|
200
200
|
"why": "fiber 留在 registry 里意味着它仍被宿主认为存活,重挂会重复。",
|
|
201
201
|
"fix": "await fiber.dispose() 后检查 registry.size 与 runtime.fibers;不要把 fiber 存到模块级全局。",
|
|
202
|
-
"docs": "docs/
|
|
202
|
+
"docs": "docs/entry.md#runtime-surface",
|
|
203
203
|
"severityHint": "fail"
|
|
204
204
|
},
|
|
205
205
|
"C-7.5": {
|
|
206
206
|
"title": "dispose 必须 await 到 quiescence",
|
|
207
207
|
"why": "只发 dispose 请求不等完成,测试会假绿而资源仍在释放中。",
|
|
208
208
|
"fix": "await fiber.dispose(),必要时再 await ctx.root.fiber.await();不要用 fire-and-forget。",
|
|
209
|
-
"docs": "docs/
|
|
209
|
+
"docs": "docs/entry.md#runtime-surface",
|
|
210
210
|
"severityHint": "fail"
|
|
211
211
|
},
|
|
212
212
|
"C-8": {
|
|
213
213
|
"title": "重挂必须幂等、冷重装可重复",
|
|
214
214
|
"why": "restart/remount 累积状态或 revision 不推进,会让热更新看起来成功实际没重载。",
|
|
215
215
|
"fix": "把模块级缓存清掉或移入 fiber;重复 restart() 后对比 effect/registry/reflect 快照;确认 revision/epoch 推进。",
|
|
216
|
-
"docs": "docs/
|
|
216
|
+
"docs": "docs/entry.md#runtime-surface",
|
|
217
217
|
"severityHint": "fail"
|
|
218
218
|
},
|
|
219
219
|
"C-8.1": {
|
|
220
220
|
"title": "连续 restart 不累积 effect",
|
|
221
221
|
"why": "第二次 restart 后 effect 数量/标签漂移,说明 disposer 没清干净。",
|
|
222
222
|
"fix": "每次 effect 都有稳定 label 与 disposer;restart 前后做归一化快照比较。",
|
|
223
|
-
"docs": "docs/
|
|
223
|
+
"docs": "docs/entry.md#runtime-surface",
|
|
224
224
|
"severityHint": "fail"
|
|
225
225
|
},
|
|
226
226
|
"C-8.2": {
|
|
227
227
|
"title": "restart 必须推进 revision/epoch",
|
|
228
228
|
"why": "被 internal/update 监听者 veto 时,size 可能不变但插件没真正重载。",
|
|
229
229
|
"fix": "在测试里断言 revision/epoch 前进;检查是否有 update 监听器吞掉重启,必要时用私有适配层观测并记录 WARN。",
|
|
230
|
-
"docs": "docs/
|
|
230
|
+
"docs": "docs/entry.md#runtime-surface",
|
|
231
231
|
"severityHint": "warn"
|
|
232
232
|
},
|
|
233
233
|
"C-8.3": {
|
|
234
234
|
"title": "冷重装后快照一致",
|
|
235
235
|
"why": "registry.delete 后重新 plugin 若状态不同,说明有跨实例残留。",
|
|
236
236
|
"fix": "清掉模块级 Map/globalThis 缓存;比较两轮装载后的归一化快照。",
|
|
237
|
-
"docs": "docs/
|
|
237
|
+
"docs": "docs/entry.md#runtime-surface",
|
|
238
238
|
"severityHint": "fail"
|
|
239
239
|
},
|
|
240
240
|
"C-9": {
|
|
241
241
|
"title": "声明与实测必须交叉一致",
|
|
242
242
|
"why": "声明 provide/inject 与实测不符会让依赖解析、重挂和权限判断全部失真。",
|
|
243
243
|
"fix": "用 L1 实测核对:声明的 provide 必须注册,inject 必须真实读取;多报/少报分别修声明或代码。",
|
|
244
|
-
"docs": "docs/
|
|
244
|
+
"docs": "docs/entry.md#runtime-surface",
|
|
245
245
|
"severityHint": "fail"
|
|
246
246
|
},
|
|
247
247
|
"C-9.1": {
|
|
248
248
|
"title": "声明 provide 必须在实测中注册",
|
|
249
249
|
"why": "缺一个注册,依赖方会拿到 undefined 或一直 PENDING。",
|
|
250
250
|
"fix": "在 apply 里注册每个声明的服务;或从 export const provide 删掉未实现的项。",
|
|
251
|
-
"docs": "docs/
|
|
251
|
+
"docs": "docs/entry.md#runtime-surface",
|
|
252
252
|
"severityHint": "fail"
|
|
253
253
|
},
|
|
254
254
|
"C-9.2": {
|
|
255
255
|
"title": "实测服务必须写进声明",
|
|
256
256
|
"why": "多注册的公开服务没有声明,用户/市场看不到它,卸载时也难以核对。",
|
|
257
257
|
"fix": "把多出的公开服务补进 provide,或改成内部/命名空间服务;不要静默暴露。",
|
|
258
|
-
"docs": "docs/
|
|
258
|
+
"docs": "docs/entry.md#runtime-surface",
|
|
259
259
|
"severityHint": "warn"
|
|
260
260
|
},
|
|
261
261
|
"C-9.3": {
|
|
262
262
|
"title": "inject 必须真的被读取",
|
|
263
263
|
"why": "多声明 inject 会让无关服务替换时也触发插件重挂。",
|
|
264
264
|
"fix": "删掉代码里从未 ctx.<service> 读取的 inject;需要可选依赖时用 ctx.get()。",
|
|
265
|
-
"docs": "docs/
|
|
265
|
+
"docs": "docs/entry.md#runtime-surface",
|
|
266
266
|
"severityHint": "warn"
|
|
267
267
|
},
|
|
268
268
|
"C-10": {
|
|
@@ -304,42 +304,42 @@
|
|
|
304
304
|
"title": "权限面必须声明",
|
|
305
305
|
"why": "dsh.capabilities 是装载期声明;漏报高风险能力会让用户看不到插件能做什么。",
|
|
306
306
|
"fix": "在 dsh.capabilities 列出所有实际使用的宿主能力(闭集 ID);字段存在后漏报会 FAIL。",
|
|
307
|
-
"docs": "docs/entry.md#
|
|
307
|
+
"docs": "docs/entry.md#capability-triggers",
|
|
308
308
|
"severityHint": "fail"
|
|
309
309
|
},
|
|
310
310
|
"C-11.1": {
|
|
311
311
|
"title": "capabilities 必须是闭集内的字符串数组",
|
|
312
312
|
"why": "未知 ID/非数组无法被市场/UI 解析,等于没声明。",
|
|
313
313
|
"fix": "用 \"capabilities\": [\"fs:read\", \"tools:register\"];只从 15 个闭集 ID 里取,不要空数组占位。",
|
|
314
|
-
"docs": "docs/entry.md#
|
|
314
|
+
"docs": "docs/entry.md#capability-triggers",
|
|
315
315
|
"severityHint": "fail"
|
|
316
316
|
},
|
|
317
317
|
"C-11.2": {
|
|
318
318
|
"title": "高信号触发必须申报能力",
|
|
319
319
|
"why": "代码用了 ctx.tools.register/ctx.webServer 等却不声明,市场无法提示风险。",
|
|
320
320
|
"fix": "按 details 的 file:line 找到触发点,把对应能力加入 dsh.capabilities(如 tools:register、network:ingress);字段缺失时先补字段。",
|
|
321
|
-
"docs": "docs/entry.md#
|
|
321
|
+
"docs": "docs/entry.md#capability-triggers",
|
|
322
322
|
"severityHint": "fail"
|
|
323
323
|
},
|
|
324
324
|
"C-11.3": {
|
|
325
325
|
"title": "不得默认启用 plugin-manager/tools",
|
|
326
326
|
"why": "打开它等于把“模型自安装”能力放给所有会话,越过 profile 的安装门。",
|
|
327
327
|
"fix": "从 bundle patch 删除/禁用 @deepseek-ai/dsh-plugin-manager/tools;确需安装能力时声明 plugin:install 并走显式审批。",
|
|
328
|
-
"docs": "docs/entry.md#
|
|
328
|
+
"docs": "docs/entry.md#capability-triggers",
|
|
329
329
|
"severityHint": "fail"
|
|
330
330
|
},
|
|
331
331
|
"C-11.4": {
|
|
332
332
|
"title": "danger-full-access 字面量要收敛",
|
|
333
333
|
"why": "真实授权/命令上下文里的 danger-full-access 会绕过沙箱;即使是文档字符串也会误导。",
|
|
334
334
|
"fix": "用最小权限 sandboxPolicy 替代;把 danger-full-access 从 .set()/.resolve()/spawn args 里删掉;只保留在文档字符串里的说明也要标注。",
|
|
335
|
-
"docs": "docs/entry.md#
|
|
335
|
+
"docs": "docs/entry.md#capability-triggers",
|
|
336
336
|
"severityHint": "warn"
|
|
337
337
|
},
|
|
338
338
|
"C-11.5": {
|
|
339
339
|
"title": "声明了能力但实测没触发",
|
|
340
340
|
"why": "过度声明会误导用户,也会让权限面看起来比实际大。",
|
|
341
341
|
"fix": "删掉未使用的 capability,或补上实际调用;动态触发无法静态确认时在 README 说明。",
|
|
342
|
-
"docs": "docs/entry.md#
|
|
342
|
+
"docs": "docs/entry.md#capability-triggers",
|
|
343
343
|
"severityHint": "warn"
|
|
344
344
|
},
|
|
345
345
|
"C-12": {
|
|
@@ -395,28 +395,28 @@
|
|
|
395
395
|
"title": "高风险类别必须标注",
|
|
396
396
|
"why": "标签是市场/用户识别 prompt 修改、第三方模型、远程访问、镜像的唯一声明面。",
|
|
397
397
|
"fix": "按能力触发补 dsh.labels;镜像同时写 dsh.upstream;不要用 official/verified/certified/secure/audited。",
|
|
398
|
-
"docs": "docs/entry.md#
|
|
398
|
+
"docs": "docs/entry.md#labels-and-mirror",
|
|
399
399
|
"severityHint": "fail"
|
|
400
400
|
},
|
|
401
401
|
"C-13.1": {
|
|
402
402
|
"title": "labels 必须是闭集内的字符串数组",
|
|
403
403
|
"why": "未知标签会被市场丢弃或误读,等于没标。",
|
|
404
404
|
"fix": "只用 prompt-modification、red-team、third-party-model-provider、remote-access、mirror;不要空数组占位。",
|
|
405
|
-
"docs": "docs/entry.md#
|
|
405
|
+
"docs": "docs/entry.md#labels-and-mirror",
|
|
406
406
|
"severityHint": "fail"
|
|
407
407
|
},
|
|
408
408
|
"C-13.2": {
|
|
409
409
|
"title": "能力触发必须补对应标签",
|
|
410
410
|
"why": "声明了 system-prompt:write 等能力却不打标签,用户看不到高风险类别。",
|
|
411
411
|
"fix": "按映射补标签:system-prompt:write→prompt-modification;llm:adapter+network:egress→third-party-model-provider;network:ingress→remote-access;dsh.upstream→mirror。",
|
|
412
|
-
"docs": "docs/entry.md#
|
|
412
|
+
"docs": "docs/entry.md#labels-and-mirror",
|
|
413
413
|
"severityHint": "fail"
|
|
414
414
|
},
|
|
415
415
|
"C-13.3": {
|
|
416
416
|
"title": "dsh.upstream 必须是合法 https URL 且不自指",
|
|
417
417
|
"why": "镜像/分叉不写上游或指向自己,用户无法追溯来源。",
|
|
418
418
|
"fix": "写 \"dsh\": { \"upstream\": \"https://github.com/owner/repo\" },不要填自己的 repository;同时加 mirror 标签。",
|
|
419
|
-
"docs": "docs/entry.md#
|
|
419
|
+
"docs": "docs/entry.md#labels-and-mirror",
|
|
420
420
|
"severityHint": "fail"
|
|
421
421
|
},
|
|
422
422
|
"C-13.4": {
|
|
@@ -430,7 +430,7 @@
|
|
|
430
430
|
"title": "red-team 标签要配 usageScope",
|
|
431
431
|
"why": "红队类插件风险高,只有标签没有使用范围说明,用户无法判断边界。",
|
|
432
432
|
"fix": "加 \"dsh\": { \"usageScope\": \"...\" } 说明授权范围与禁止用途;没有红队用途就删掉该标签。",
|
|
433
|
-
"docs": "docs/entry.md#
|
|
433
|
+
"docs": "docs/entry.md#labels-and-mirror",
|
|
434
434
|
"severityHint": "warn"
|
|
435
435
|
},
|
|
436
436
|
"C-14": {
|
|
@@ -444,35 +444,35 @@
|
|
|
444
444
|
"title": "bundle patch 必须可解析",
|
|
445
445
|
"why": "G0 过不了,后续 G1-G3 都无法开始,bundle 安装即失败。",
|
|
446
446
|
"fix": "修 cordis.patch.yml 的 YAML/字段;确认 dsh.bundle.patch 指向的文件能被宿主解析,再跑 bundle smoke。",
|
|
447
|
-
"docs": "docs/entry.md#
|
|
447
|
+
"docs": "docs/entry.md#runtime-surface",
|
|
448
448
|
"severityHint": "fail"
|
|
449
449
|
},
|
|
450
450
|
"G1": {
|
|
451
451
|
"title": "patch 目标行必须能解析",
|
|
452
452
|
"why": "G1 失败说明 patch 行的 name/target 对不上,宿主无法合成 profile。",
|
|
453
453
|
"fix": "按宿主 patch 语法修 name/target;确认目标包在 host farm 中存在;用 --base/--web/--bare 提供真实宿主再复跑。",
|
|
454
|
-
"docs": "docs/entry.md#
|
|
454
|
+
"docs": "docs/entry.md#runtime-surface",
|
|
455
455
|
"severityHint": "fail"
|
|
456
456
|
},
|
|
457
457
|
"G2": {
|
|
458
458
|
"title": "宿主兼容性门必须接受",
|
|
459
459
|
"why": "G2 reject 表示宿主会直接跳过该 bundle,用户装了也不会生效。",
|
|
460
460
|
"fix": "修 engines.dsh/peer 范围到宿主接受;核对 host 的 plugin-compatibility 结果,不要靠豁免当通过。",
|
|
461
|
-
"docs": "docs/entry.md#
|
|
461
|
+
"docs": "docs/entry.md#runtime-surface",
|
|
462
462
|
"severityHint": "fail"
|
|
463
463
|
},
|
|
464
464
|
"G3": {
|
|
465
465
|
"title": "bundle 行必须全部 ACTIVE",
|
|
466
466
|
"why": "G3 partial 表示目标 profile 没提供某些服务,bundle 只挂上了一部分。",
|
|
467
467
|
"fix": "用 --host/--base/--web/--bare 提供完整目标 profile;检查 patch 行的 inject/provide 与宿主服务是否匹配;partial 不能写成通过。",
|
|
468
|
-
"docs": "docs/entry.md#
|
|
468
|
+
"docs": "docs/entry.md#runtime-surface",
|
|
469
469
|
"severityHint": "fail"
|
|
470
470
|
},
|
|
471
471
|
"G4": {
|
|
472
472
|
"title": "client 形态必须能被宿主识别",
|
|
473
473
|
"why": "G4 失败说明 dsh.client 没有 package-root 行或 client 导出缺失,客户端加载不到。",
|
|
474
474
|
"fix": "补 dsh.client 的 package-root 行与 client 导出;确认构建产物在 files 里;用 --entry-runtime server-entry/client probe 复跑。",
|
|
475
|
-
"docs": "docs/entry.md#
|
|
475
|
+
"docs": "docs/entry.md#client-files",
|
|
476
476
|
"severityHint": "fail"
|
|
477
477
|
}
|
|
478
478
|
}
|