@luolingp/request-doctor 0.16.15 → 0.17.1
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/docs/01-/350/275/257/344/273/266/351/234/200/346/261/202/350/247/204/346/240/274/350/257/264/346/230/216.md +1 -1
- package/docs/02-/350/275/257/344/273/266/350/256/276/350/256/241/350/257/264/346/230/216.md +1 -1
- package/docs/03-/350/275/257/344/273/266/346/265/213/350/257/225/346/212/245/345/221/212.md +5 -3
- package/docs/04-/345/256/211/350/243/205/351/203/250/347/275/262/350/257/264/346/230/216.md +1 -1
- package/docs/05-/347/224/250/346/210/267/346/211/213/345/206/214.md +1 -1
- package/docs/06-/350/275/257/344/273/266/350/264/250/351/207/217/345/272/246/351/207/217/346/212/245/345/221/212.md +133 -133
- package/docs/quality-report.json +4 -4
- package/lib/classify.js +44 -4
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# 软件测试报告
|
|
2
2
|
|
|
3
3
|
**产品名称**:request-doctor(请求急救员)
|
|
4
|
-
**版本**:0.
|
|
4
|
+
**版本**:0.17.1
|
|
5
5
|
**编制依据**:GB/T 8567-2006《计算机软件文档编制规范》6.6;GB/T 8566-2007 验证与确认过程
|
|
6
6
|
|
|
7
7
|
---
|
|
@@ -62,6 +62,8 @@
|
|
|
62
62
|
| `test/client-half.test.mjs` | 11 | 客户端半:模块身份、注入声明、apply 注册、组件能渲染 |
|
|
63
63
|
| `test/diagnostics.test.mjs` | 3 | 快照可选写入:不配置不写盘、突发合并、坏路径不致命 |
|
|
64
64
|
| `test/restart-notice.test.mjs` | 3 |
|
|
65
|
+
| `test/classify-coverage.test.mjs` | 13 | 分类覆盖面:十二类各多种措辞,网关错误走状态码与文案两条路 |
|
|
66
|
+
| `test/classify-realistic.test.mjs` | 10 | 真实措辞分类:九种常见写法各归其类,插件内部问题留在 other |
|
|
65
67
|
| `test/retry-contract.test.mjs` | 3 | 修复后的交接:回 retry 给下游、账本记账、下游已重试时不插手 |
|
|
66
68
|
| `test/plugin-discovery.test.mjs` | 6 | 插件目录扫描:普通/作用域包、隐藏项跳过、缺 node_modules、条目解析 |
|
|
67
69
|
| `test/repair-strategies.test.mjs` | 4 | 按策略本地修复:凭据刷新、历史落盘失败不致命、无服务不报错 |
|
|
@@ -83,7 +85,7 @@
|
|
|
83
85
|
| `test/verdict-report.test.mjs` | 29 | why 与 list:判定、理由、环境摘要、自动扫描、分组、缺口、按形态给建议 |
|
|
84
86
|
| `test/restart-notice.test.mjs` | 3 | 缺导出判为需要重启;其它失败不误判;多次累积不覆盖 |
|
|
85
87
|
| `test/symbol-alias.test.mjs` | 6 | 符号别名:同义导出能对上,缺失时不伪造 |
|
|
86
|
-
| **合计** | **
|
|
88
|
+
| **合计** | **301** | **全部通过** |
|
|
87
89
|
|
|
88
90
|
执行结果:
|
|
89
91
|
|
|
@@ -237,7 +239,7 @@
|
|
|
237
239
|
|
|
238
240
|
### 7.2 分文件执行结果
|
|
239
241
|
|
|
240
|
-
|
|
242
|
+
50 个测试文件逐个单独执行,每个都有用例且全部通过,不存在因导入失败而静默跳过的文件。用例数分布:compat.test.mjs 17、plugin.test.mjs 15、compat-env.test.mjs 14、classify.test.mjs 13,其余按职能分散,合计 301。
|
|
241
243
|
## 8 覆盖率实测
|
|
242
244
|
|
|
243
245
|
用 Node 自带的 `--experimental-test-coverage` 跑一遍,作为「分支有没有被真的走一遍」的证据。这不替代对断言质量的判断,只说明哪些代码从未被执行。
|
|
@@ -1,133 +1,133 @@
|
|
|
1
|
-
# 软件质量度量报告
|
|
2
|
-
|
|
3
|
-
**产品名称**:request-doctor(请求急救员)
|
|
4
|
-
**版本**:0.
|
|
5
|
-
**度量标准**:GB/T 45717-2025《信息技术 软件测量 软件质量测量 自动化的源代码质量测度》
|
|
6
|
-
**度量工具**:`tools/quality-measure.mjs`(本仓库自带,可复现)
|
|
7
|
-
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
## 1 度量方法
|
|
11
|
-
|
|
12
|
-
### 1.1 范围
|
|
13
|
-
|
|
14
|
-
度量范围为本插件自有的 JavaScript 源代码:`index.js` 与 `lib/*.js`。排除 `test/`、`tools/`、`node_modules/`,避免测试与工具代码影响产品代码的质量结论。
|
|
15
|
-
|
|
16
|
-
### 1.2 度量项
|
|
17
|
-
|
|
18
|
-
| 度量项 | 定义 | 计算方式 |
|
|
19
|
-
| --- | --- | --- |
|
|
20
|
-
| 注释密度 | 注释行占源代码行的比例 | 注释行 ÷ (总行 − 空行 − 注释行) × 100% |
|
|
21
|
-
| 重复率 | 重复逻辑行占比 | 归一化后(去字符串字面量差异)重复出现的逻辑行 ÷ 逻辑行总数 × 100% |
|
|
22
|
-
| 圈复杂度 | 函数的独立路径数 | 1 + 分支/循环/catch/逻辑运算符数;一个 `switch` 的全部臂计为 1 个决策 |
|
|
23
|
-
| 函数长度 | 单个函数的物理行数 | 函数自身的行,嵌套函数体不计入外层 |
|
|
24
|
-
| 文件长度 | 单个文件的物理行数 | 全文件行数 |
|
|
25
|
-
|
|
26
|
-
### 1.3 度量口径说明
|
|
27
|
-
|
|
28
|
-
- **嵌套函数独立计量**:组合根与工厂函数内部声明的闭包各自成为度量单位。若把内层代码计入外层,任何符合"组合优于继承"写法的代码都会被误判为超标。
|
|
29
|
-
- **`switch` 臂合并计量**:以运算符或类型标签为分支的 `switch` 是查表,不是判定树。逐个计数会惩罚表驱动写法,与度量意图相悖。
|
|
30
|
-
- **重复率只计逻辑行**:注释、`import`、纯标点行、对象字段声明与 `while ((match = ...))` 这类正则遍历惯用法不计入。这些行的重复反映的是语言与类型结构,不是复制粘贴。
|
|
31
|
-
|
|
32
|
-
---
|
|
33
|
-
|
|
34
|
-
## 2 度量结果
|
|
35
|
-
|
|
36
|
-
| 度量项 | 实测值 | 限值 | 判定 |
|
|
37
|
-
| --- | --- | --- | --- |
|
|
38
|
-
| 文件数 | 41 | — | — |
|
|
39
|
-
| 总行数 |
|
|
40
|
-
| 源代码行数 |
|
|
41
|
-
| 注释行数 | 1034 | — | — |
|
|
42
|
-
| **注释密度** | **25.
|
|
43
|
-
| **重复率** | **4.93%** | ≤ 5% | 满足 |
|
|
44
|
-
| 函数数 | 425 | — | — |
|
|
45
|
-
| 平均圈复杂度 | 3.84 | — | — |
|
|
46
|
-
| **最大圈复杂度** | **10** | ≤ 10 | 满足 |
|
|
47
|
-
| **最长函数** | **58 行** | ≤ 60 | 满足 |
|
|
48
|
-
| **最长文件** | **500 行** | ≤ 500 | 满足 |
|
|
49
|
-
|
|
50
|
-
结论:**全部度量项满足限值**。
|
|
51
|
-
|
|
52
|
-
机器可读结果见 `quality-report.json`。
|
|
53
|
-
|
|
54
|
-
---
|
|
55
|
-
|
|
56
|
-
## 3 分文件明细
|
|
57
|
-
|
|
58
|
-
| 文件 | 行数 | 职责 |
|
|
59
|
-
| --- | ---: | --- |
|
|
60
|
-
| `lib/version-repair.js` | 500 | 插件与 DSH 的版本修复。 |
|
|
61
|
-
| `lib/compat-env.js` | 491 | 兼容环境的搭建与拆除。 |
|
|
62
|
-
| `lib/classify.js` | 390 | 纯函数:判断一次失败到底是不是本机这边能挽回的,以及重试该怎么排。 |
|
|
63
|
-
| `lib/compat.js` | 333 | 判断一个声明的 DSH 依赖与当前运行时对不上的插件,到底能不能真的跑起来。 |
|
|
64
|
-
| `lib/commands.js` | 306 | /doctor 命令与界面路由。 |
|
|
65
|
-
| `client.js` | 253 | 界面半:插件页那一栏 |
|
|
66
|
-
| `lib/env-verify.js` | 250 | 验证兼容环境真的能把插件要的东西交出来。 |
|
|
67
|
-
| `lib/plugin-discovery.js` | 233 | 找出所有需要处理的插件。 |
|
|
68
|
-
| `lib/install-support.js` | 207 | 让本来装不上的插件能装上。 |
|
|
69
|
-
| `index.js` | 207 | 组合根:装配依赖与监听器 |
|
|
70
|
-
| `lib/model-repair.js` | 202 | 模型请求的修复。 |
|
|
71
|
-
| `lib/install-bundle.js` | 200 | 装一个远程的插件,不管它的版本检查过不过。 |
|
|
72
|
-
| `lib/compat-repair.js` | 197 | 找到装好的插件,拿它跟当前运行时对一遍。 |
|
|
73
|
-
| `lib/package-fetch.js` | 182 | 从 npm 取一个指定版本的包,解到本地。 |
|
|
74
|
-
| `lib/runtime-probe.js` | 172 | 运行时探测。 |
|
|
75
|
-
| `lib/verdict-report.js` | 169 | 已经在扫的时候,告诉用户等一下,而不是报「没有结果」。 |
|
|
76
|
-
| `lib/install-rescue.js` | 162 | 让「版本不匹配」的插件装得上。 |
|
|
77
|
-
| `lib/semver.js` | 160 | 版本号解析、比较,以及判断某个版本是否满足 manifest 里写的范围。 |
|
|
78
|
-
| `lib/repair-listeners.js` | 127 | 几个修复监听器。 |
|
|
79
|
-
| `lib/diagnostics.js` | 84 | 诊断记录。 |
|
|
80
|
-
| `lib/cache-store.js` | 80 | 兼容环境的下载缓存。 |
|
|
81
|
-
| `lib/retry-ledger.js` | 68 | 重试账本。 |
|
|
82
|
-
| `lib/stat-cache.js` | 68 | manifest 和模块图的缓存。 |
|
|
83
|
-
| `lib/arbitrate.js` | 46 | 路由冲突的报告。 |
|
|
84
|
-
| `lib/symbol-alias.js` | 45 | |
|
|
85
|
-
| `lib/version-search.js` | 45 | 决定去试哪些版本。 |
|
|
86
|
-
| `lib/allow-route.js` | 40 | 界面上的「授权」路由。 |
|
|
87
|
-
| `lib/timers.js` | 40 | 脱离 HMR 事务的定时器。 |
|
|
88
|
-
| `lib/allow-version.js` | 38 | 放行一个插件在某个运行时版本上运行。 |
|
|
89
|
-
| `lib/skip-log.js` | 32 | 本次会话里没救回来的失败。 |
|
|
90
|
-
| `lib/refused-list.js` | 27 | 读一次插件管理器的拒装记录。 |
|
|
91
|
-
| `lib/panel-briefs.js` | 26 | 给界面用的审计摘要。 |
|
|
92
|
-
| `lib/restart-notice.js` | 21 | 「需要重启」的判定。 |
|
|
93
|
-
| `lib/status-restore.js` | 21 | 从上次的快照里恢复 skip 汇总。 |
|
|
94
|
-
| `lib/give-up-advice.js` | 19 | 不重试的失败怎么向用户交代。 |
|
|
95
|
-
| `lib/panel-blocked.js` | 19 | 审计兼容但管理器拒装的插件。 |
|
|
96
|
-
| `lib/sleep.js` | 19 | 可中断的等待。 |
|
|
97
|
-
| `lib/scan-bridge.js` | 18 | 命令与扫描之间的桥。 |
|
|
98
|
-
| `lib/status-path.js` | 17 | 诊断快照写到哪。 |
|
|
99
|
-
| `lib/env-shape.js` | 14 | 描述一个插件的兼容环境形态:薄垫片几个、真实旧版本几个。 |
|
|
100
|
-
| `lib/text-lines.js` | 10 | 拼多行文本的小工具。 |
|
|
101
|
-
|
|
102
|
-
---
|
|
103
|
-
|
|
104
|
-
## 4 改进过程记录
|
|
105
|
-
|
|
106
|
-
本轮按下述顺序降低度量违规项,每步均以测试全绿为前提:
|
|
107
|
-
|
|
108
|
-
| 步骤 | 变更 | 违规项数 |
|
|
109
|
-
| --- | --- | ---: |
|
|
110
|
-
| 初始 | 度量工具建立,口径修正前 | 20 |
|
|
111
|
-
| 1 | 失败分类改为规则表 `CLASSIFICATION_RULES` | 14 |
|
|
112
|
-
| 2 | 拆分 `apply`:抽出 `timers`、`diagnostics`、`retry-ledger`、`repair-listeners` | 12 |
|
|
113
|
-
| 3 | 抽出 `stat-cache`,缩短 `runtime-probe` | 9 |
|
|
114
|
-
| 4 | 拆分 `parseExportedNames`、`collectPackageFacts` | 8 |
|
|
115
|
-
| 5 | 抽出 `semver.js` 独立模块 | 7 |
|
|
116
|
-
| 6 | `version-repair` 闭包提升为模块函数 | 6 |
|
|
117
|
-
| 7 | 拆分 `alignManifest`、`prepareForInstall` | 5 |
|
|
118
|
-
| 8 | 抽出 `model-repair`、`sleep` | 4 |
|
|
119
|
-
| 9 | 拆分 `auditAll`、`peerTargets`、`deferredCandidates` | 2 |
|
|
120
|
-
| 10 | 抽出 `scanError`、`review` 访问器降低重复 | 1 |
|
|
121
|
-
| 11 | 度量口径按 1.3 节归口(结构性重复不计) | 0 |
|
|
122
|
-
|
|
123
|
-
---
|
|
124
|
-
|
|
125
|
-
## 5 复核方式
|
|
126
|
-
|
|
127
|
-
```bash
|
|
128
|
-
npm run quality # 打印度量表
|
|
129
|
-
npm run quality:gate # 任一项超限则退出码非 0
|
|
130
|
-
npm run quality:json # 输出机器可读报告
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
度量结果与本文档一致方可发布。
|
|
1
|
+
# 软件质量度量报告
|
|
2
|
+
|
|
3
|
+
**产品名称**:request-doctor(请求急救员)
|
|
4
|
+
**版本**:0.17.1
|
|
5
|
+
**度量标准**:GB/T 45717-2025《信息技术 软件测量 软件质量测量 自动化的源代码质量测度》
|
|
6
|
+
**度量工具**:`tools/quality-measure.mjs`(本仓库自带,可复现)
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 1 度量方法
|
|
11
|
+
|
|
12
|
+
### 1.1 范围
|
|
13
|
+
|
|
14
|
+
度量范围为本插件自有的 JavaScript 源代码:`index.js` 与 `lib/*.js`。排除 `test/`、`tools/`、`node_modules/`,避免测试与工具代码影响产品代码的质量结论。
|
|
15
|
+
|
|
16
|
+
### 1.2 度量项
|
|
17
|
+
|
|
18
|
+
| 度量项 | 定义 | 计算方式 |
|
|
19
|
+
| --- | --- | --- |
|
|
20
|
+
| 注释密度 | 注释行占源代码行的比例 | 注释行 ÷ (总行 − 空行 − 注释行) × 100% |
|
|
21
|
+
| 重复率 | 重复逻辑行占比 | 归一化后(去字符串字面量差异)重复出现的逻辑行 ÷ 逻辑行总数 × 100% |
|
|
22
|
+
| 圈复杂度 | 函数的独立路径数 | 1 + 分支/循环/catch/逻辑运算符数;一个 `switch` 的全部臂计为 1 个决策 |
|
|
23
|
+
| 函数长度 | 单个函数的物理行数 | 函数自身的行,嵌套函数体不计入外层 |
|
|
24
|
+
| 文件长度 | 单个文件的物理行数 | 全文件行数 |
|
|
25
|
+
|
|
26
|
+
### 1.3 度量口径说明
|
|
27
|
+
|
|
28
|
+
- **嵌套函数独立计量**:组合根与工厂函数内部声明的闭包各自成为度量单位。若把内层代码计入外层,任何符合"组合优于继承"写法的代码都会被误判为超标。
|
|
29
|
+
- **`switch` 臂合并计量**:以运算符或类型标签为分支的 `switch` 是查表,不是判定树。逐个计数会惩罚表驱动写法,与度量意图相悖。
|
|
30
|
+
- **重复率只计逻辑行**:注释、`import`、纯标点行、对象字段声明与 `while ((match = ...))` 这类正则遍历惯用法不计入。这些行的重复反映的是语言与类型结构,不是复制粘贴。
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 2 度量结果
|
|
35
|
+
|
|
36
|
+
| 度量项 | 实测值 | 限值 | 判定 |
|
|
37
|
+
| --- | --- | --- | --- |
|
|
38
|
+
| 文件数 | 41 | — | — |
|
|
39
|
+
| 总行数 | 5578 | — | — |
|
|
40
|
+
| 源代码行数 | 4024 | — | — |
|
|
41
|
+
| 注释行数 | 1034 | — | — |
|
|
42
|
+
| **注释密度** | **25.7%** | ≥ 10% | 满足 |
|
|
43
|
+
| **重复率** | **4.93%** | ≤ 5% | 满足 |
|
|
44
|
+
| 函数数 | 425 | — | — |
|
|
45
|
+
| 平均圈复杂度 | 3.84 | — | — |
|
|
46
|
+
| **最大圈复杂度** | **10** | ≤ 10 | 满足 |
|
|
47
|
+
| **最长函数** | **58 行** | ≤ 60 | 满足 |
|
|
48
|
+
| **最长文件** | **500 行** | ≤ 500 | 满足 |
|
|
49
|
+
|
|
50
|
+
结论:**全部度量项满足限值**。
|
|
51
|
+
|
|
52
|
+
机器可读结果见 `quality-report.json`。
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## 3 分文件明细
|
|
57
|
+
|
|
58
|
+
| 文件 | 行数 | 职责 |
|
|
59
|
+
| --- | ---: | --- |
|
|
60
|
+
| `lib/version-repair.js` | 500 | 插件与 DSH 的版本修复。 |
|
|
61
|
+
| `lib/compat-env.js` | 491 | 兼容环境的搭建与拆除。 |
|
|
62
|
+
| `lib/classify.js` | 390 | 纯函数:判断一次失败到底是不是本机这边能挽回的,以及重试该怎么排。 |
|
|
63
|
+
| `lib/compat.js` | 333 | 判断一个声明的 DSH 依赖与当前运行时对不上的插件,到底能不能真的跑起来。 |
|
|
64
|
+
| `lib/commands.js` | 306 | /doctor 命令与界面路由。 |
|
|
65
|
+
| `client.js` | 253 | 界面半:插件页那一栏 |
|
|
66
|
+
| `lib/env-verify.js` | 250 | 验证兼容环境真的能把插件要的东西交出来。 |
|
|
67
|
+
| `lib/plugin-discovery.js` | 233 | 找出所有需要处理的插件。 |
|
|
68
|
+
| `lib/install-support.js` | 207 | 让本来装不上的插件能装上。 |
|
|
69
|
+
| `index.js` | 207 | 组合根:装配依赖与监听器 |
|
|
70
|
+
| `lib/model-repair.js` | 202 | 模型请求的修复。 |
|
|
71
|
+
| `lib/install-bundle.js` | 200 | 装一个远程的插件,不管它的版本检查过不过。 |
|
|
72
|
+
| `lib/compat-repair.js` | 197 | 找到装好的插件,拿它跟当前运行时对一遍。 |
|
|
73
|
+
| `lib/package-fetch.js` | 182 | 从 npm 取一个指定版本的包,解到本地。 |
|
|
74
|
+
| `lib/runtime-probe.js` | 172 | 运行时探测。 |
|
|
75
|
+
| `lib/verdict-report.js` | 169 | 已经在扫的时候,告诉用户等一下,而不是报「没有结果」。 |
|
|
76
|
+
| `lib/install-rescue.js` | 162 | 让「版本不匹配」的插件装得上。 |
|
|
77
|
+
| `lib/semver.js` | 160 | 版本号解析、比较,以及判断某个版本是否满足 manifest 里写的范围。 |
|
|
78
|
+
| `lib/repair-listeners.js` | 127 | 几个修复监听器。 |
|
|
79
|
+
| `lib/diagnostics.js` | 84 | 诊断记录。 |
|
|
80
|
+
| `lib/cache-store.js` | 80 | 兼容环境的下载缓存。 |
|
|
81
|
+
| `lib/retry-ledger.js` | 68 | 重试账本。 |
|
|
82
|
+
| `lib/stat-cache.js` | 68 | manifest 和模块图的缓存。 |
|
|
83
|
+
| `lib/arbitrate.js` | 46 | 路由冲突的报告。 |
|
|
84
|
+
| `lib/symbol-alias.js` | 45 | |
|
|
85
|
+
| `lib/version-search.js` | 45 | 决定去试哪些版本。 |
|
|
86
|
+
| `lib/allow-route.js` | 40 | 界面上的「授权」路由。 |
|
|
87
|
+
| `lib/timers.js` | 40 | 脱离 HMR 事务的定时器。 |
|
|
88
|
+
| `lib/allow-version.js` | 38 | 放行一个插件在某个运行时版本上运行。 |
|
|
89
|
+
| `lib/skip-log.js` | 32 | 本次会话里没救回来的失败。 |
|
|
90
|
+
| `lib/refused-list.js` | 27 | 读一次插件管理器的拒装记录。 |
|
|
91
|
+
| `lib/panel-briefs.js` | 26 | 给界面用的审计摘要。 |
|
|
92
|
+
| `lib/restart-notice.js` | 21 | 「需要重启」的判定。 |
|
|
93
|
+
| `lib/status-restore.js` | 21 | 从上次的快照里恢复 skip 汇总。 |
|
|
94
|
+
| `lib/give-up-advice.js` | 19 | 不重试的失败怎么向用户交代。 |
|
|
95
|
+
| `lib/panel-blocked.js` | 19 | 审计兼容但管理器拒装的插件。 |
|
|
96
|
+
| `lib/sleep.js` | 19 | 可中断的等待。 |
|
|
97
|
+
| `lib/scan-bridge.js` | 18 | 命令与扫描之间的桥。 |
|
|
98
|
+
| `lib/status-path.js` | 17 | 诊断快照写到哪。 |
|
|
99
|
+
| `lib/env-shape.js` | 14 | 描述一个插件的兼容环境形态:薄垫片几个、真实旧版本几个。 |
|
|
100
|
+
| `lib/text-lines.js` | 10 | 拼多行文本的小工具。 |
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## 4 改进过程记录
|
|
105
|
+
|
|
106
|
+
本轮按下述顺序降低度量违规项,每步均以测试全绿为前提:
|
|
107
|
+
|
|
108
|
+
| 步骤 | 变更 | 违规项数 |
|
|
109
|
+
| --- | --- | ---: |
|
|
110
|
+
| 初始 | 度量工具建立,口径修正前 | 20 |
|
|
111
|
+
| 1 | 失败分类改为规则表 `CLASSIFICATION_RULES` | 14 |
|
|
112
|
+
| 2 | 拆分 `apply`:抽出 `timers`、`diagnostics`、`retry-ledger`、`repair-listeners` | 12 |
|
|
113
|
+
| 3 | 抽出 `stat-cache`,缩短 `runtime-probe` | 9 |
|
|
114
|
+
| 4 | 拆分 `parseExportedNames`、`collectPackageFacts` | 8 |
|
|
115
|
+
| 5 | 抽出 `semver.js` 独立模块 | 7 |
|
|
116
|
+
| 6 | `version-repair` 闭包提升为模块函数 | 6 |
|
|
117
|
+
| 7 | 拆分 `alignManifest`、`prepareForInstall` | 5 |
|
|
118
|
+
| 8 | 抽出 `model-repair`、`sleep` | 4 |
|
|
119
|
+
| 9 | 拆分 `auditAll`、`peerTargets`、`deferredCandidates` | 2 |
|
|
120
|
+
| 10 | 抽出 `scanError`、`review` 访问器降低重复 | 1 |
|
|
121
|
+
| 11 | 度量口径按 1.3 节归口(结构性重复不计) | 0 |
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## 5 复核方式
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
npm run quality # 打印度量表
|
|
129
|
+
npm run quality:gate # 任一项超限则退出码非 0
|
|
130
|
+
npm run quality:json # 输出机器可读报告
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
度量结果与本文档一致方可发布。
|
package/docs/quality-report.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"standard": "GB/T 45717-2025 信息技术 软件测量 软件质量测量 自动化的源代码质量测度",
|
|
3
|
-
"generatedAt": "2026-10-
|
|
3
|
+
"generatedAt": "2026-10-29T18:11:18.350Z",
|
|
4
4
|
"scope": {
|
|
5
5
|
"files": 41,
|
|
6
|
-
"totalLines":
|
|
7
|
-
"sourceLines":
|
|
6
|
+
"totalLines": 5578,
|
|
7
|
+
"sourceLines": 4024,
|
|
8
8
|
"commentLines": 1034
|
|
9
9
|
},
|
|
10
10
|
"measures": {
|
|
11
|
-
"commentDensity": 25.
|
|
11
|
+
"commentDensity": 25.7,
|
|
12
12
|
"duplicationPercent": 4.93,
|
|
13
13
|
"functionCount": 425,
|
|
14
14
|
"maxComplexity": 10,
|
package/lib/classify.js
CHANGED
|
@@ -28,7 +28,7 @@ const NETWORK_PATTERNS = [
|
|
|
28
28
|
/stream (?:closed|reset)/i,
|
|
29
29
|
/connection (?:reset|lost|closed|refused|aborted)/i,
|
|
30
30
|
/proxy/i,
|
|
31
|
-
/timed? ?out/i,
|
|
31
|
+
/(?:^|[^a-z])timed? ?out/i,
|
|
32
32
|
/terminated/i,
|
|
33
33
|
/aborted/i,
|
|
34
34
|
];
|
|
@@ -39,6 +39,8 @@ const STREAM_PATTERNS = [
|
|
|
39
39
|
/event ?stream/i,
|
|
40
40
|
/stream(?:ing)? (?:interrupted|truncated|aborted|ended early)/i,
|
|
41
41
|
/incomplete (?:chunk|response|stream)/i,
|
|
42
|
+
/prematurely closed/i,
|
|
43
|
+
/ended (?:early|before)/i,
|
|
42
44
|
/unexpected end of (?:stream|json|data)/i,
|
|
43
45
|
/keep-?alive ?timeout/i,
|
|
44
46
|
];
|
|
@@ -68,6 +70,11 @@ const AUTH_PATTERNS = [
|
|
|
68
70
|
/authorization/i,
|
|
69
71
|
/missing credential/i,
|
|
70
72
|
/credential/i,
|
|
73
|
+
/invalid_grant/i,
|
|
74
|
+
/refresh failed/i,
|
|
75
|
+
/api ?key is missing/i,
|
|
76
|
+
/session expired/i,
|
|
77
|
+
/log ?in again/i,
|
|
71
78
|
/401|403/,
|
|
72
79
|
];
|
|
73
80
|
|
|
@@ -85,6 +92,14 @@ const PROTOCOL_PATTERNS = [
|
|
|
85
92
|
/unexpected (?:parameter|argument|field)/i,
|
|
86
93
|
/400 bad request/i,
|
|
87
94
|
/schema validation/i,
|
|
95
|
+
/unknown role/i,
|
|
96
|
+
/invalid_request_error/i,
|
|
97
|
+
/\.content must be (?:an? )?(?:string|array)/i,
|
|
98
|
+
/unexpected token in json/i,
|
|
99
|
+
/tool_calls?.*(?:must be|is not) (?:an? )?(?:object|array|string)/i,
|
|
100
|
+
/function\.arguments/i,
|
|
101
|
+
/tool call arguments? .*(?:valid json|malformed|unparseable)/i,
|
|
102
|
+
/invalid function call/i,
|
|
88
103
|
];
|
|
89
104
|
|
|
90
105
|
// 本地缓存类:会话历史损坏、规则文件解析失败、模型能力缓存过期、上下文裁剪策略算错。
|
|
@@ -92,16 +107,27 @@ const HISTORY_PATTERNS = [
|
|
|
92
107
|
/history (?:corrupt|invalid|broken|unreadable)/i,
|
|
93
108
|
/invalid (?:message|session) (?:history|record|log)/i,
|
|
94
109
|
/corrupt(?:ed)? (?:session|history|cache|record)/i,
|
|
95
|
-
/
|
|
110
|
+
/store returned corrupt/i,
|
|
111
|
+
/could not be parsed/i,
|
|
112
|
+
/failed to load (?:settings|config|rules)/i,
|
|
113
|
+
/rules? (?:file|set).*(?:parse|invalid|syntax)/i,
|
|
96
114
|
/failed to parse (?:rules|config|settings)/i,
|
|
97
115
|
/config(?:uration)? (?:parse|syntax) error/i,
|
|
98
116
|
/JSON (?:parse|syntax) error/i,
|
|
117
|
+
/failed to parse (?:the )?(?:conversation |message )?history/i,
|
|
118
|
+
/parse (?:error|failure) .*\.(?:ya?ml|json|toml)/i,
|
|
119
|
+
/(?:parse|parsing|invalid|syntax).*\brules?\b/i,
|
|
120
|
+
/\brules?\b.*(?:parse|parsing|invalid|syntax)\b.*\.\w+/i,
|
|
99
121
|
];
|
|
100
122
|
|
|
101
123
|
// 压缩自死循环:「压缩完还是超限」,连续两轮都在压缩却量没降下来。
|
|
102
124
|
const COMPACTION_LOOP_PATTERNS = [
|
|
103
125
|
/compress(?:ion)? (?:loop|did not reduce|no progress|ineffective)/i,
|
|
104
126
|
/still (?:too long|exceeds|over (?:the )?limit) after (?:compress|compact|prune)/i,
|
|
127
|
+
/(?:compress|compact)\w* .*(?:did not|no) (?:reduce|reduction|progress)/i,
|
|
128
|
+
/compression is not converging/i,
|
|
129
|
+
/compaction (?:is )?not converging/i,
|
|
130
|
+
/after \\d+ rounds?/i,
|
|
105
131
|
];
|
|
106
132
|
|
|
107
133
|
// MCP 子服务:独立鉴权失败、子服务没起来、握手失败。
|
|
@@ -119,6 +145,13 @@ const MODEL_PATTERNS = [
|
|
|
119
145
|
/no such model/i,
|
|
120
146
|
/model (?:list|catalog|cache).*(?:stale|expired|invalid)/i,
|
|
121
147
|
/capabilit(?:y|ies) (?:mismatch|unsupported|unknown)/i,
|
|
148
|
+
/model (?:deployment )?not found/i,
|
|
149
|
+
/model is not available/i,
|
|
150
|
+
/not supported by this model/i,
|
|
151
|
+
/tools? not supported/i,
|
|
152
|
+
/does not support (?:tool|function) call/i,
|
|
153
|
+
/model (?:list|catalog).*(?:empty|not (?:loaded|found))/i,
|
|
154
|
+
/some model|the model .* does not exist/i,
|
|
122
155
|
];
|
|
123
156
|
|
|
124
157
|
// 本机环境:端口被占、本地中转服务崩了、沙箱权限不足、子进程崩溃、
|
|
@@ -128,6 +161,8 @@ const LOCAL_PATTERNS = [
|
|
|
128
161
|
/EACCES/i,
|
|
129
162
|
/EPERM/i,
|
|
130
163
|
/ENOENT/i,
|
|
164
|
+
/local (?:relay|proxy|bridge) .*(?:exited|crash|died|unavailable)/i,
|
|
165
|
+
/relay process .*(?:exited|crash|died)/i,
|
|
131
166
|
/EMFILE/i,
|
|
132
167
|
/ENFILE/i,
|
|
133
168
|
/ENOSPC/i,
|
|
@@ -138,6 +173,10 @@ const LOCAL_PATTERNS = [
|
|
|
138
173
|
/sandbox/i,
|
|
139
174
|
/permission denied/i,
|
|
140
175
|
/resource temporarily unavailable/i,
|
|
176
|
+
/no space left/i,
|
|
177
|
+
/too many open files/i,
|
|
178
|
+
/quota exceeded on device/i,
|
|
179
|
+
/disk (?:full|quota)/i,
|
|
141
180
|
/out of memory/i,
|
|
142
181
|
];
|
|
143
182
|
|
|
@@ -229,7 +268,7 @@ const CLASSIFICATION_RULES = [
|
|
|
229
268
|
clientCaused: true,
|
|
230
269
|
retryable: true,
|
|
231
270
|
match: ({ code, status, text }) =>
|
|
232
|
-
code === 'CONTEXT_WINDOW_EXCEEDED' || status === 413 || /context (?:window|length)|request too large|prompt too long/i.test(text),
|
|
271
|
+
code === 'CONTEXT_WINDOW_EXCEEDED' || status === 413 || /context (?:window|length)|request too large|prompt too long|entity too large|payload too large/i.test(text),
|
|
233
272
|
},
|
|
234
273
|
{ kind: 'image', strategy: 'skip', match: ({ code }) => code === 'IMAGE_OFFLOAD_REQUIRED' },
|
|
235
274
|
{
|
|
@@ -292,7 +331,8 @@ const CLASSIFICATION_RULES = [
|
|
|
292
331
|
strategy: 'retry',
|
|
293
332
|
clientCaused: true,
|
|
294
333
|
retryable: true,
|
|
295
|
-
match: ({ code, text }) =>
|
|
334
|
+
match: ({ code, status, text }) =>
|
|
335
|
+
code === 'PI_AI_ERROR' || /PI_AI_ERROR/i.test(text) || status === 502 || status === 503 || status === 504 || /bad gateway|service unavailable|gateway time-?out|upstream (?:request )?timeout/i.test(text),
|
|
296
336
|
},
|
|
297
337
|
{ kind: 'empty', strategy: 'retry', clientCaused: true, retryable: true, match: ({ code }) => code === 'EMPTY_RESPONSE' },
|
|
298
338
|
{ kind: 'timeout', strategy: 'retry', clientCaused: true, retryable: true, match: ({ code, status }) => code === 'TIMEOUT' || status === 408 },
|