dsh-math-calculator 2.1.0 → 2.2.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/CHANGELOG.md +951 -0
- package/README.md +64 -50
- package/dsh.plugin.json +2 -2
- package/lib/__wtest.txt +1 -0
- package/lib/awareness.js +69 -20
- package/lib/format.js +522 -13
- package/lib/formula-library-em.js +428 -0
- package/lib/formulas.js +28 -1
- package/lib/guards.js +653 -0
- package/lib/help.js +509 -0
- package/lib/index.js +1367 -212
- package/lib/ops/shared.js +547 -6
- package/lib/ops/units-op.js +116 -10
- package/lib/ops/workspace-op.js +10 -0
- package/lib/playbook.js +32 -7
- package/lib/types/format.d.ts +31 -1
- package/lib/types/formula-library-em.d.ts +28 -0
- package/lib/types/formulas.d.ts +2 -0
- package/lib/types/guards.d.ts +255 -0
- package/lib/types/help.d.ts +70 -0
- package/lib/types/index.d.ts +34 -1
- package/lib/types/ops/shared.d.ts +87 -3
- package/lib/types/playbook.d.ts +28 -0
- package/lib/types/units-data.d.ts +253 -0
- package/lib/types/units.d.ts +54 -4
- package/lib/types/workspace.d.ts +50 -0
- package/lib/units-data.js +1037 -0
- package/lib/units.js +82 -117
- package/lib/workspace.js +54 -0
- package/package.json +1 -1
- package/src/awareness.ts +69 -20
- package/src/format.ts +520 -12
- package/src/formula-library-em.ts +435 -0
- package/src/formulas.ts +35 -4
- package/src/guards.ts +673 -0
- package/src/help.ts +543 -0
- package/src/index.ts +1502 -213
- package/src/ops/shared.ts +589 -9
- package/src/ops/units-op.ts +125 -9
- package/src/ops/workspace-op.ts +10 -0
- package/src/playbook.ts +32 -7
- package/src/units-data.ts +1128 -0
- package/src/units.ts +149 -130
- package/src/workspace.ts +65 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,957 @@
|
|
|
2
2
|
|
|
3
3
|
本项目遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/) 与 [语义化版本](https://semver.org/lang/zh-CN/)。
|
|
4
4
|
|
|
5
|
+
## [2.2.0] — 2026-11-03
|
|
6
|
+
|
|
7
|
+
按三份实测反馈修缺陷。**重点:这一版修的都是「结果看着正常但其实是错的」**——
|
|
8
|
+
它们比直接报错更危险,因为看不出来。
|
|
9
|
+
|
|
10
|
+
分两批:前半是三份文档里已实测确认的真问题;后半是对三份文档逐条复核后,
|
|
11
|
+
把「没做」与「做了却看不出来」分开处理的结果。
|
|
12
|
+
|
|
13
|
+
### 修复
|
|
14
|
+
|
|
15
|
+
- **小数值被定点截断,误差可达 5.8%**(实测最危险的一条)。
|
|
16
|
+
|
|
17
|
+
`σ = 5.670374419e-8` 在 8 位小数下曾显示成 `0.00000006` ——
|
|
18
|
+
相对误差 5.8%,而数字看着完全正常。判据原本是「会不会四舍五入成 0」,
|
|
19
|
+
但 `5.67e-8` 并不归零,只是**错了**,后者远比归零隐蔽。
|
|
20
|
+
|
|
21
|
+
现在判据改为**相对误差超过万分之一就自动改用科学计数法**:
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
修复前 0.00000006 相对误差 5.8%
|
|
25
|
+
修复后 5.67037442e-8
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
同时把显示精度提示收窄成「只在真丢精度时附一句具体说明」,噪音从 10/10 降到 0/20。
|
|
29
|
+
提示走独立的 `notice` 字段,**不拼进 `result`**(拼进去会让 `0.1+0.2` 变成两行,
|
|
30
|
+
破坏依赖 `result` 精确相等的调用方)。
|
|
31
|
+
|
|
32
|
+
- **未定义的单字母标识符被静默当成单位**。
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
rho=2035; rho*V → 2.035 kV ← V 被当成伏特,不报错、不警告
|
|
36
|
+
rho=2035; rho*m → 2.035 km
|
|
37
|
+
rho=2035; rho*g → 2.035 kg
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
物理推演里最规范的变量名恰恰都是单字母(`m`/`V`/`W`/`T`/`g`),
|
|
41
|
+
旧行为等于**在惩罚最规范的命名习惯**。
|
|
42
|
+
|
|
43
|
+
难点:mathjs 把 `5 V`(单位)与 `rho*V`(变量)解析成**完全相同的 AST**,
|
|
44
|
+
语法层无法区分,只能看上下文。现在的判据是——与已定义变量同级、或单独出现时报错;
|
|
45
|
+
父节点是乘法且兄弟含数字(`5 V`)、或幂指数是数字(`s^2`)时照旧当单位。
|
|
46
|
+
范围只覆盖实测确认的 20 个单字母单位,且有 13 条断言专门守「真单位用法不能坏」。
|
|
47
|
+
|
|
48
|
+
- **`integral` 静默忽略 `from`/`to`**,只回不定积分。
|
|
49
|
+
|
|
50
|
+
静默忽略已传入的参数是最伤信任的行为。现在真的算 `F(to) − F(from)`。
|
|
51
|
+
顺带修掉一个精度陷阱:定积分代入**必须用 Fraction 引擎** ——
|
|
52
|
+
BigNumber 的 `1/3` 是截断小数,乘 27 回不到整数(`8.999999…`),Fraction 能得 `9`。
|
|
53
|
+
|
|
54
|
+
- **`overrides` 里拼错的 key 被静默丢弃**,公式照常出数、参数用默认值,
|
|
55
|
+
结果"合理但错误"(实测曾导致一次「236 倍缺口」误判)。
|
|
56
|
+
|
|
57
|
+
现在会点名哪些 key 已被忽略,并列出该公式的真实参数。
|
|
58
|
+
判据分清:不在 params 里、**且**不在常数表里的才算错拼 ——
|
|
59
|
+
`g`/`c`/`G` 是公式可引用的世界常数,拿它覆盖是合法用法。
|
|
60
|
+
|
|
61
|
+
### 新增
|
|
62
|
+
|
|
63
|
+
- **直觉写法**:`2**10`、`ln(10)`、`π`、`2 × 3`、`6 ÷ 2` 现在都可直接用。
|
|
64
|
+
根因是其它 operation 内部都调了 `normalizeSource`,只有 `evaluate` 与批量路径漏了;
|
|
65
|
+
归一化会跳过引号内的内容(`5 cm to "inch"` 的单位名不会被改)。
|
|
66
|
+
- **批量 label**:`expressions` 支持 `{label:"储耗比-中值", expr:"139e8/152e4"}`,
|
|
67
|
+
解决「只有顺序号区分、一度差点引错」。回显格式为 `储耗比-中值(139e8/152e4) = 9144.73684211`。
|
|
68
|
+
- **`terse:true`**:只回「表达式 = 结果」,去掉标题与统计。**失败信息绝不隐藏**,有专门断言守着。
|
|
69
|
+
|
|
70
|
+
### 新增(第二轮:参数层不再静默)
|
|
71
|
+
|
|
72
|
+
- **认不出的参数名会报错,不再静默吞掉**。
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
{operation:'evaluate', expression:'1+3', foo_bar_baz:123}
|
|
76
|
+
修复前 → ok=true, 返回 3 ← 参数被整个吞掉
|
|
77
|
+
修复后 → ok=false, unknown_argument,点名 foo_bar_baz
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
这是本轮**风险最大**的一条:三份文档里提到的 `format`、`sigfigs`、`anchor` 等
|
|
81
|
+
未实现的参数,以前都是「传了不报错、也不生效」——调用方以为做了,实际没做。
|
|
82
|
+
与 `overrides` 里 key 拼错被丢弃是同一类问题,只是发生在顶层。
|
|
83
|
+
|
|
84
|
+
白名单**从真实数据源派生**,不手写。踩过一个坑:第一版只从 `MathArgs` 接口取键,
|
|
85
|
+
而 `starMass`/`starTemp` 等 world 顶层简写参数**不在接口里**,
|
|
86
|
+
于是合法调用被自己的校验拦下(world 套件当场红)。现改为同时承认 `WORLD_KEYS`。
|
|
87
|
+
|
|
88
|
+
刻意**不做大小写归一**:试过「`DisplayPrecision` 自动映射到 `displayPrecision`」,
|
|
89
|
+
结果参数被接受却因为代码只读小写键而完全不生效——那比报错更难排查。
|
|
90
|
+
|
|
91
|
+
- **`displayPrecision: 0` 现在真的生效**(只留整数部分)。
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
修复前 {expression:'22/7', displayPrecision:0} → 3.14285714 ← 0 被当成「没给」
|
|
95
|
+
修复后 {expression:'22/7', displayPrecision:0} → 3
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
根因是入口把 `<= 0` 当作未给,而 schema 上白纸黑字写着「0-64」。
|
|
99
|
+
两处 0 的语义**刻意不同**(各有各的理由,已在两处注释里写明):
|
|
100
|
+
单次参数的 0 = 「0 位小数」,工作区 set 的 0 = 「清除固化值」。
|
|
101
|
+
|
|
102
|
+
- **语法错误现在会给括号定位,不再只说「检查括号是否配对」**。
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
缺左括号 ((1+2)/3 → 「这几个左括号没有闭合: 第 1 字符;补上 1 个 ")" 即可」
|
|
106
|
+
多右括号 (1+2)/3) → 「第 8 个字符处的 ")" 没有对应的左括号;多是前面漏了一个 "("」
|
|
107
|
+
并回显表达式,在下方标出每个括号的层级
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
不做「自动补括号」——猜错了会把报错变成一个**算错的数**,比报错糟得多。
|
|
111
|
+
|
|
112
|
+
- **英制单位补齐**:长吨/短吨/英担/英石、BTU/therm、ft·lbf/s,
|
|
113
|
+
并新增**压力量纲**(Pa/kPa/MPa/bar/atm/psi/mmHg/Torr)。
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
107000 lb → 47.7679 longton 14.7 psi → 1.01353 bar
|
|
117
|
+
1260000 BTU → 1.32937 GJ 760 mmHg → 101325 Pa
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
实测反馈里这些系数被手打过 8 次以上——「记错数」变成「打错名」,
|
|
121
|
+
后者更容易被发现。这也是文档二 P1-1 里真正可行的那一半。
|
|
122
|
+
|
|
123
|
+
- **help 补全 derivation 的 29 个子命令**(按用途分组,并注明各子命令的关键参数),
|
|
124
|
+
以及**账本闭合配方**(用 `expressions` + `label` 逐项列值 + 差值,
|
|
125
|
+
不做成 PASS/FAIL:差 3 与差 3% 是两种情况,压成一个布尔就全糊了)。
|
|
126
|
+
|
|
127
|
+
### 新增(带单位结果的说明注释,按用户 2026-11-06 要求)
|
|
128
|
+
|
|
129
|
+
用户原话:「面向 AI 的运算信息最好把信息注释写到位。」
|
|
130
|
+
|
|
131
|
+
实测对比:**同一个数,两条路径的信息量差得远**:
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
units 操作 → 30 里 = 15 km【代入过程】【注意】成熟的说明
|
|
135
|
+
evaluate → 87.78 Mt notice 为空,什么都没说
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
模型看到 `87.78 Mt` 并不知道它是 8778 万吨、量级 10⁷ 吨。
|
|
139
|
+
而这正是长链推演里最容易数错 0 的地方。
|
|
140
|
+
|
|
141
|
+
现在带单位的结果会补一句(走 `notice`,不动 `result` 数据通道):
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
2.66e8 * 330 kg → 87.78 Mt
|
|
145
|
+
notice: 注:87.78 Mt = 8.778e7 t,约 8778 万吨,量级 10⁷。
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
三样信息,都是模型判断「这个数合不合理」时真正要用的:
|
|
149
|
+
展开成基准单位(便于和其它数比)、中文量级说法(语料的习惯表达)、量级。
|
|
150
|
+
|
|
151
|
+
**批量路径也有**(跟在结果行后):
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
年产(2.66e8*330 kg) = 87.78 Mt|注:87.78 Mt = 8.778e7 t,约 8778 万吨,量级 10⁷。
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## 判据刻意收紧:只在 ≥ 10⁴ 时注
|
|
158
|
+
|
|
159
|
+
试过「带前缀就注」,结果 `3 km = 3000 m,量级 10³` —— 注了等于没注,反而占行宽。
|
|
160
|
+
日常量级人本来就有直觉,只有跨到万吨级/亿米级才值得说一句。
|
|
161
|
+
|
|
162
|
+
复合单位(`9.81 m/s^2`)不注 —— 量级词在那个位置不适用。
|
|
163
|
+
|
|
164
|
+
## 顺带修掉的一个失效
|
|
165
|
+
|
|
166
|
+
批量显示行的量级标注走 `annotateMagnitude`,而它内部做 `Number(text)` ——
|
|
167
|
+
`87.78 Mt` 会得到 NaN,于是**带单位时那个标注静默失效**。
|
|
168
|
+
现在按结果形态分派:纯数字走 `(~10^N)`,带单位走新的说明注释。
|
|
169
|
+
|
|
170
|
+
### 修订(SI 前缀可斟酌使用,按用户 2026-11-06 追问)
|
|
171
|
+
|
|
172
|
+
上一版把 SI 前缀**全部禁用**、超出常用档一律丢给科学计数法(`1e6 t`),
|
|
173
|
+
那是矫枉过正。用户纠正:「K,M,G,T,P,E,Z,Y,R,Q,不是禁止,可以斟酌使用。」
|
|
174
|
+
|
|
175
|
+
`Mt`(百万吨)、`Gt`(十亿吨)、`kt`(千吨)、`Gm` 那些是**正经写法**,
|
|
176
|
+
工程与气候文献里常见;`1e12 t` 反而不如 `1 Tt` 好读。
|
|
177
|
+
|
|
178
|
+
规则改成两层:
|
|
179
|
+
|
|
180
|
+
1. **先按阶梯选常用单位** —— 保证不会出现 `Tg`、`Mm`、`ML` 这种冷门组合
|
|
181
|
+
2. **数值仍超出该档时,在常用单位上叠前缀** —— `t` → `kt` / `Mt` / `Gt` / `Tt` …
|
|
182
|
+
|
|
183
|
+
```
|
|
184
|
+
1e12 g → 1 Mt (不是 1 Tg,也不是 1e6 t)
|
|
185
|
+
1e15 g → 1 Gt
|
|
186
|
+
1e9 m → 1 Gm
|
|
187
|
+
1e12 W → 1 TW
|
|
188
|
+
1e18 J → 1 EJ
|
|
189
|
+
2.66亿吨 → 266 Mt (2.66 亿吨的可读写法)
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
长度/功率/能量把高阶档位**直接摊平在阶梯表里**(`Mm/Gm/Tm/Pm/Em`),
|
|
193
|
+
而不是靠前缀叠加 —— 因为长度阶梯里已有 `km`(自带前缀),
|
|
194
|
+
再叠一层会拼出 `kkm` 这种无效组合。质量则用叠加,因为阶梯只到 `t`(不带前缀)。
|
|
195
|
+
|
|
196
|
+
**踩过一个倍率错**:`steps` 算出来是「除以 10³ 几次」,
|
|
197
|
+
而前缀数组 0 号是 `k`,所以下标应是 `steps - 1`。
|
|
198
|
+
第一版直接用 `steps`,于是 `1e4 t` 输出成 `10 Mt` —— 差一千倍。
|
|
199
|
+
|
|
200
|
+
**同时守住的不变量**:整数一律完整输出(`10^20+5` 一位不少),
|
|
201
|
+
常用值(`1 kg`/`3 km`/`2 L`/`1 m^3`)不受影响。
|
|
202
|
+
|
|
203
|
+
### 修复(输出单位归位,按用户 2026-11-06 指示)
|
|
204
|
+
|
|
205
|
+
用户原话:**「重量单位使用常见的 kg/公斤、t/吨,大数用科学计数法,
|
|
206
|
+
其他单位依次类推用常用的公制单位。」**
|
|
207
|
+
|
|
208
|
+
实测确认的问题:mathjs 会按数量级自动选 SI 前缀,但它**只按数量级走**,
|
|
209
|
+
不管现实中人说哪个词。于是:
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
一个很大的重量 → 1 Tg(太克) ← 现实中没人这么说
|
|
213
|
+
1e6 m → 1 Mm(兆米) ← 没人这么说
|
|
214
|
+
1e6 s → 1 Ms(兆秒) ← 没人这么说
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
改为**按量纲的常用单位阶梯表**(`src/format.ts` 的 `PREFERRED_UNIT_LADDER`):
|
|
218
|
+
|
|
219
|
+
| 量纲 | 阶梯(从大到小取第一个跨过的档) |
|
|
220
|
+
|---|---|
|
|
221
|
+
| 质量 | t / kg / g / mg |
|
|
222
|
+
| 长度 | km / m / cm / mm / µm |
|
|
223
|
+
| 时间 | year / day / h / min / s |
|
|
224
|
+
| 功率 | GW / MW / kW / W |
|
|
225
|
+
| 能量 | TJ / GJ / MJ / kJ / J |
|
|
226
|
+
| 压强 | MPa / kPa / Pa |
|
|
227
|
+
|
|
228
|
+
效果:
|
|
229
|
+
|
|
230
|
+
```
|
|
231
|
+
1e12 g → 1e6 t (不是 1 Tg)
|
|
232
|
+
1e6 m → 1000 km (不是 1 Mm)
|
|
233
|
+
1e6 s → 11.57 day (不是 1 Ms)
|
|
234
|
+
2 kg * 1e6 → 2000 t
|
|
235
|
+
0.5 g → 500 mg
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
**超出最大常用档时用科学计数法配该单位**(`1e6 t`、`1e9 km`),
|
|
239
|
+
而不是引入更冷门的前缀。
|
|
240
|
+
|
|
241
|
+
## 三个踩过的坑(都已写成注释)
|
|
242
|
+
|
|
243
|
+
**1. `unit.value` 已经是基准单位的数值,不要再乘前缀**
|
|
244
|
+
第一次乘了 `prefix.value`(`2 kg` 变成 0.002 kg),
|
|
245
|
+
第二次乘了 baseFactor(`1 t` 变成 1e6 kg)。
|
|
246
|
+
两次都是「凭直觉推断第三方库内部表示」而不是实测反推 —— 教训明确。
|
|
247
|
+
|
|
248
|
+
**2. 整数绝不能为「好读」改科学计数法**
|
|
249
|
+
试过「≥1e15 改科学计数法」,被 **12 条断言当场打回**:
|
|
250
|
+
那违反本项目最硬的不变量「整数永不丢位」——
|
|
251
|
+
`10^20` 与 `10^20+5` 会长得一样,那是丢信息不是简洁。
|
|
252
|
+
大数占行宽的问题改由**批量显示补千分位**解决(纯视觉分组、不改值)。
|
|
253
|
+
|
|
254
|
+
**3. 体积刻意不做归位**
|
|
255
|
+
试过 L↔m³ 互换,结果 `1000 L` 变 `1 m^3` 而 `1 m^3` 变 `1000 L` ——
|
|
256
|
+
两者互相吞吐。体积的「常用写法」本身就不统一(水用 L、土方用 m³),
|
|
257
|
+
强行归位只会改掉调用方给的语义,收益为零。
|
|
258
|
+
|
|
259
|
+
## 面向 AI 的注释补到位(用户要求)
|
|
260
|
+
|
|
261
|
+
`help` 新增「【输出单位】」一段,直接写明:
|
|
262
|
+
|
|
263
|
+
```
|
|
264
|
+
质量 mg/g/kg/t | 长度 mm/cm/m/km | 时间 s/min/h/day/year
|
|
265
|
+
功率 W/kW/MW/GW | 能量 J/kJ/MJ/GJ/TJ | 压强 Pa/kPa/MPa
|
|
266
|
+
超出最大档 → 科学计数法配该单位(1e6 t、1e9 km)
|
|
267
|
+
1e12 g → 1e6 t(不是 1 Tg);1e6 m → 1000 km(不是 1 Mm)
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
这样模型在调用前就知道结果会长什么样,不必事后猜测。
|
|
271
|
+
|
|
272
|
+
### 说明(输出单位归位)
|
|
273
|
+
|
|
274
|
+
- 受影响的断言按**新契约**更新(3 处):
|
|
275
|
+
`1 时辰 + 30 分钟` 从 `9 ks` 改为 `2.5 h`;
|
|
276
|
+
`2.66亿吨` 从 `266 Tg` 改为 `2.66e8 t`;
|
|
277
|
+
`2.66e8*330 kg` 从 `87.78 Tg(= 8778 万吨)` 改为 `8.778e7 t` ——
|
|
278
|
+
后两条的旧断言断言的正是本次要消掉的 `Tg`。
|
|
279
|
+
- 旧的「SI 前缀补中文量级参照」(`annotateMetricPrefix`) 仍然保留:
|
|
280
|
+
它只在质量 ≥ 万吨时补一句 `(= 8778 万吨)`,而单位归位后
|
|
281
|
+
`Tg` 不再出现,这条注释自然不再触发 —— 两条机制不冲突,一层兜底。
|
|
282
|
+
- `help` 5943 字符(上限 6000)、定义总长 6230(上限 6231)。
|
|
283
|
+
|
|
284
|
+
### 修复(按 2026-11-06 第二份实测报告)
|
|
285
|
+
|
|
286
|
+
一份 99 层架空世界观的设定推演,约 18 次调用 / 130 余个算式。
|
|
287
|
+
它的 P0 是**中文量级词**——恰好是上一轮修中文单位时漏掉的一环:
|
|
288
|
+
单位表收了「里/丈/亩/斤」,却没收入「万/亿/万亿」。
|
|
289
|
+
|
|
290
|
+
报告作者两次把「吨」当成「亿吨」,起因就是必须手写 `/1e8`:
|
|
291
|
+
|
|
292
|
+
```
|
|
293
|
+
0.591e8 * 330 / 1e3 → 19503000 (~10⁷) 被读成「1.95 万吨」,实为 1,950 万吨
|
|
294
|
+
2.66e8 * 330 / 1e3 / 1e8 → 0.8778 被读成「878 万吨」,实为 8,780 万吨
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
**「两步除法」本身就是错误源**,而工具原本可以替调用方消掉这一步。
|
|
298
|
+
|
|
299
|
+
- **中文量级词 `万` / `亿` / `万亿` 现在可直接参与运算**。
|
|
300
|
+
|
|
301
|
+
```
|
|
302
|
+
2.66亿 * 330 → 87780000000
|
|
303
|
+
450 亿吨 / 31.39 亿吨 → 14.33577572 (比值无量纲)
|
|
304
|
+
3万亿 → 3000000000000
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
实现走**乘数展开**(`2.66亿` → `(2.66 * 1e8)`),而不是把它们注册成单位:
|
|
308
|
+
单位表的机制是「factor × 基准量纲」,而量级词是无量纲乘数 ——
|
|
309
|
+
硬塞进去会把「亿米」和「亿吨」搞成同一种东西。
|
|
310
|
+
|
|
311
|
+
三个必须注意的细节(都已写成注释与断言):
|
|
312
|
+
· **长词优先**:`万亿` 必须排在 `万` 与 `亿` 之前,否则 `3万亿` 会被拆错
|
|
313
|
+
· **展开后要再包一层括号**:否则 `450 亿吨 / 31.39 亿吨` 因乘除左结合变成先除再乘,
|
|
314
|
+
结果带上 `Mg^2` 量纲 —— 数值对、量纲错,这种最难发现
|
|
315
|
+
· **「人」「畜」在量级词后面是计数**,不是功率单位(`2.66亿人` 不能变成 `19.95 GW`)
|
|
316
|
+
|
|
317
|
+
- **数字数组不再静默全失败**。
|
|
318
|
+
|
|
319
|
+
```
|
|
320
|
+
expressions: [0.5, 9.9, 10]
|
|
321
|
+
修复前 → (空表达式)→ 跳过 ×3,成功 0
|
|
322
|
+
修复后 → 0.5 = 0.5 / 9.9 = 9.9 / 10 = 10
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
这是**类型错误被伪装成内容错误** —— 用户传的是合法数字,
|
|
326
|
+
工具说「空表达式」,会让人去翻数据源而不是检查类型。纯数字元素现在自动转字符串。
|
|
327
|
+
|
|
328
|
+
- **非法变量键不再中止整批**。
|
|
329
|
+
|
|
330
|
+
```
|
|
331
|
+
variables: {"P":1000, "Q":5, "人口":1}
|
|
332
|
+
修复前 → ok:false,连合法的 P*330 都没算
|
|
333
|
+
修复后 → P*330 = 330000 照算,notice 里点名「人口」被跳过
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
这类语料的概念名几乎全是中文(人口/粮食/石料),用户第一反应就会用中文命名。
|
|
337
|
+
现在合法键照常进作用域,非法的记进 notice —— **算出来的数仍然是对的**。
|
|
338
|
+
不做「支持中文变量名」:那要放宽 mathjs 的词法,会引入新的歧义。
|
|
339
|
+
|
|
340
|
+
- **语法错误给子类型与位置**,不再一律说「检查括号是否配对」。
|
|
341
|
+
|
|
342
|
+
```
|
|
343
|
+
1,000 * 2 → 「表达式里有千分位逗号,去掉即可」(旧提示说查括号,指错了方向)
|
|
344
|
+
/ 112.5e8 → 「运算符位置不对(第 1 个字符附近「/ 112.5」)」
|
|
345
|
+
某中文*2 → 「表达式里有中文;中文单位与量级词可直接写,其它请改英文变量名」
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
**顺带修掉一个很隐蔽的漏判**:这条正则原来写的是 `SyntaxError`(无空格),
|
|
349
|
+
而 mathjs 报的是 `Syntax error`(有空格)——于是这类错误落到兜底分支,
|
|
350
|
+
表现为「错误类型对、但没有任何 hint」。报告里 `2.66亿 * 330` 无提示就是这个原因。
|
|
351
|
+
靠对照实验才揪出来(`1+*2` 有提示而 `某中文*2` 没有)。
|
|
352
|
+
|
|
353
|
+
- **质量 SI 前缀补中文量级参照**。
|
|
354
|
+
|
|
355
|
+
```
|
|
356
|
+
2.66e8*330 kg → 87.78 Tg(= 8778 万吨)
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
「87.78 Tg」读不出「8,778 万吨」,而中文语料里这个量级就叫亿吨。
|
|
360
|
+
只对「质量 × 克」这一族、且 ≥ 万吨时补 —— `1 Gg(= 1000 吨)` 那种注了等于没注。
|
|
361
|
+
|
|
362
|
+
- **大整数补千分位**(只在批量显示里,`result` 数据通道不变)。
|
|
363
|
+
|
|
364
|
+
```
|
|
365
|
+
1e20*3 → 300000000000000000000(300,000,000,000,000,000,000) (~10²⁰)
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
报告原话:「一条 21 位数字就占满一行,且位数多到无法目视核位
|
|
369
|
+
——本次我数错过一次 0 的个数。」
|
|
370
|
+
|
|
371
|
+
- **三角函数按弧度算时给一句说明**。
|
|
372
|
+
|
|
373
|
+
```
|
|
374
|
+
sin(30) → -0.98803162,notice 提示「按弧度;要角度请写 sin(30 deg)」
|
|
375
|
+
sin(30 deg) → 0.5,不提示
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
中文工程语境里 `sin(30)` 的默认读法是 30 度。按数学惯例走弧度是对的,
|
|
379
|
+
但不给提示就是静默错误 —— `-0.988` 看起来像个正常数。
|
|
380
|
+
判据保守:只对三角函数 + 裸数字 + 数值在 [0,360] 时提示。
|
|
381
|
+
|
|
382
|
+
### 说明(实测报告 1106b)
|
|
383
|
+
|
|
384
|
+
- 新增 `test/report-1106b.mjs`(37 项)。第 7 节守「既有能力一个不能坏」:
|
|
385
|
+
`(10^20+1)-10^20 = 1`、`2**3`、`sin(30 deg)`、中文单位混算、`solve` 精确解、
|
|
386
|
+
`units` 换算全部逐条验证。
|
|
387
|
+
- `workspace-variables.mjs` 的契约随「非法键不中止」更新(18 → 19 项):
|
|
388
|
+
断言从「非法键导致整批失败」改为「非法键不进作用域 + 明确告知」。
|
|
389
|
+
- 一条没有照做:**「输出优先 k/M/G 封顶、显式换算禁用 e 记数」**。
|
|
390
|
+
那会改变所有既有输出、破坏依赖精确文本的调用方;
|
|
391
|
+
改成「加一句中文量级参照」是追加信息,不动主文本 —— 与本项目一贯取舍一致。
|
|
392
|
+
|
|
393
|
+
### 修复(按 2026-11-06 实测报告)
|
|
394
|
+
|
|
395
|
+
一份 200 余条表达式的实测报告,**先讲自己的错、再讲工具的缺陷**,每条带可复现调用。
|
|
396
|
+
逐条实测后确认 6 条真缺陷,另有 3 条判断有误(未照做,理由记在评审记录里)。
|
|
397
|
+
|
|
398
|
+
- **批量求值失败时顶层 `ok` 仍是 `true`**(最严重的一条)。
|
|
399
|
+
|
|
400
|
+
```
|
|
401
|
+
{expressions:[{label:'未定义变量', expr:'unknown_var*2'}], terse:true}
|
|
402
|
+
→ result 里写着「失败[unknown_symbol]」
|
|
403
|
+
→ ok: true ← 失败却报成功
|
|
404
|
+
→ error: undefined
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
报告原话:「我多次写 `if (!r.ok)` 来判断成败,得到的结果是『永远成功』
|
|
408
|
+
——因为 `ok` 永远是 `true`。」任何依赖 `ok` 的自动化流程都会把失败当成功。
|
|
409
|
+
|
|
410
|
+
现在 `ok` 按失败数决定,并补三个结构化字段:
|
|
411
|
+
`partial`(有失败但仍有可用条目)、`failed`、`succeeded`。
|
|
412
|
+
刻意**不**塞 `error` —— 那是「批量里某条错」,不是「整个调用错」,
|
|
413
|
+
硬塞一个会把「只有第 3 条错」读成「全部错」。
|
|
414
|
+
|
|
415
|
+
- **label 量级警告 100% 误报**(上一轮防呆层引入的回归)。
|
|
416
|
+
|
|
417
|
+
```
|
|
418
|
+
{label:"1亿棵树日产台", expr:"1e8*25000"}
|
|
419
|
+
→ ⚠ label 含「亿」,若按字面读成「亿」则为 2.50e20
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
`1亿棵树日产台` 是**条件描述**(以 1 亿棵树为输入),不是「结果单位是亿」。
|
|
423
|
+
旧判据用 `label.includes(词)`,于是每个含量级词的 label 都会触发一条无意义警告。
|
|
424
|
+
|
|
425
|
+
判据改为「量级词必须处在单位位置」:结尾、或紧接短单位/数量名词。
|
|
426
|
+
条件描述(后面还跟一长串)一律放过。
|
|
427
|
+
|
|
428
|
+
**同时修掉一个更隐蔽的漏报**:`年耗H2O万吨` 这类 label 里的数字是
|
|
429
|
+
**化学式下标**,不是「一天产出 2 亿」那种条件。旧判据见到数字就放过,
|
|
430
|
+
导致报告里「同一个错犯了四次」的原始案例全都不检查。
|
|
431
|
+
|
|
432
|
+
- **中文单位不能参与表达式运算**。
|
|
433
|
+
|
|
434
|
+
```
|
|
435
|
+
3 km + 500 m → 3.5 km ✓
|
|
436
|
+
1 里 + 3 米 → Syntax error ✗
|
|
437
|
+
5 亩 + 100 m² → Syntax error ✗
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
两条路径的单位表没打通(`units` 认「里」「亩」,表达式不认)。
|
|
441
|
+
|
|
442
|
+
实现走**文本归一化**而不是往 mathjs 注册中文单位 ——
|
|
443
|
+
因为 `buildMath` 里刻意删掉了 `createUnit`(那是安全边界的一部分)。
|
|
444
|
+
现在「数字 + 中文单位」在解析前展开成「数字 * 系数 基准单位」:
|
|
445
|
+
|
|
446
|
+
```
|
|
447
|
+
1 里 + 3 米 → 503 m
|
|
448
|
+
3 公里 + 500 米 → 3.5 km(公里优先于里,不被拆错)
|
|
449
|
+
2 斤 + 300 克 → 1.3 kg
|
|
450
|
+
1 丈 + 2 尺 → 3.84 m
|
|
451
|
+
5 亩 + 100 m² → 3433.33 m²
|
|
452
|
+
1 时辰 + 30 分钟 → 9 ks
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
顺带修掉两处相关缺陷:mathjs 不认上标(`m²` 报 Syntax error),
|
|
456
|
+
现在表达式里统一换成 `m^2`;面积别名 `km2` / `m2` 也能用。
|
|
457
|
+
|
|
458
|
+
- **`units` 的代入过程有同义重复**。
|
|
459
|
+
|
|
460
|
+
```
|
|
461
|
+
· 1 kg = 1 kg
|
|
462
|
+
· 9.0000e+15 kg = 9.0000e+15 kg
|
|
463
|
+
· 1 t = 1000 kg,故结果 = 9000000000000 t
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
前两行是废话(源单位是基准单位时,「1 X = 1 X」什么也没说明)。
|
|
467
|
+
而且它让输出**看起来有内容,其实没有** —— 这比啰嗦更值得修。
|
|
468
|
+
现在按信息量分四种情况,只写有意义的步骤。
|
|
469
|
+
|
|
470
|
+
- **`terse` 对 `units` 不生效**。
|
|
471
|
+
|
|
472
|
+
`{operation:"units", terse:true}` 原来仍返回 6 行带框。现在只回一行,
|
|
473
|
+
但**保留适用域提示**(「里在周制约 415 m」这类信息被省掉,
|
|
474
|
+
调用方会拿错朝代的值去写设定 —— 那比多几行更糟)。
|
|
475
|
+
|
|
476
|
+
- **英文全称别名缺失**:`ton` / `tonne` / `meters` / `metre` / `hectare` /
|
|
477
|
+
`grams` / `seconds` 全不认,只认缩写。而英文文献里全称极常见。
|
|
478
|
+
已在 length / mass / time / area 四个最常用量纲补齐(没有给冷门单位长别名表,
|
|
479
|
+
那是每轮计费的固定成本)。
|
|
480
|
+
|
|
481
|
+
- **`expressions` 元素里的未知键被静默忽略**(本报告未提,实测发现)。
|
|
482
|
+
|
|
483
|
+
```
|
|
484
|
+
{expressions:[{label:'a', expr:'1+1', unit:'kg/day'}]} → ok=true,unit 被丢弃
|
|
485
|
+
{expression:'1+1', unit:'kg/day'} → 报 unknown_argument ✓
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
顶层严格拦截,元素内部不查。危险在于:将来加 `unit` / `assumption`
|
|
489
|
+
这类按条参数时,它们必然写在这个位置,会被静默吞掉。
|
|
490
|
+
现在该条失败并点名键名,其余条目不受影响(保持「逐条独立」的约定)。
|
|
491
|
+
|
|
492
|
+
### 说明(实测报告 1106)
|
|
493
|
+
|
|
494
|
+
- 新增 `test/report-1106.mjs`(51 项)。
|
|
495
|
+
- **三条没有照做**(详见 `docs/实测报告1106评审.md`):
|
|
496
|
+
· 「量纲一致性检查并拒绝计算」——工具不知道你在比较,且「猜」违背项目取向
|
|
497
|
+
· 「面积单位只认上标」——诊断不准(`平方米`/`公顷` 本来就支持;
|
|
498
|
+
真正的问题是 `evaluate` 连上标都不认,已单独修)
|
|
499
|
+
· 「`workspaceVariables` 读取链路损坏」——功能可用,是 `help` 表述有歧义
|
|
500
|
+
(开关必须先 `action2:"set"` 到工作区,不能当 `evaluate` 参数传)
|
|
501
|
+
|
|
502
|
+
### 新增(防呆层:在数字旁边多放一句「这个数看起来不对劲」)
|
|
503
|
+
|
|
504
|
+
来自一份 **200 余条表达式**的实测复盘。那份文档的核心结论是:
|
|
505
|
+
|
|
506
|
+
> math_execute 现在是一个准确的算术器,但还不是一个可靠的验算伙伴。
|
|
507
|
+
> 它给数字,不给判断 —— 所以它最该做的不是算得更准(它已经很准),
|
|
508
|
+
> 而是**在数字旁边多放一句「这个数看起来不对劲」**。
|
|
509
|
+
|
|
510
|
+
文档里记录的真实事故:
|
|
511
|
+
|
|
512
|
+
```
|
|
513
|
+
2645.6*28*3600*8000/1e9 → 2133.41184
|
|
514
|
+
调用者贴上「万吨」标签 → 以此为据指控原文「错了 10 倍」
|
|
515
|
+
真相:2133 是千吨,万吨应为 /1e10 → 213.34(原文完全正确)
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
**四条年度物料全部犯同一个错、全部偏大 10 倍、全部报「成功」。**
|
|
519
|
+
|
|
520
|
+
这一版做了三件事:
|
|
521
|
+
|
|
522
|
+
**1. 量级标注** —— 裸数字旁边配 `(~10³)`
|
|
523
|
+
|
|
524
|
+
```
|
|
525
|
+
年耗N2万吨 = 2133.41184 (~10³)
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
10⁰~10³ 这个日常区间不标(标了反而吵)。
|
|
529
|
+
|
|
530
|
+
**2. label 与结果的量级核对**
|
|
531
|
+
|
|
532
|
+
label 里明确写了量级词(万/亿/千…)时,比对该量级与结果本身的数量级:
|
|
533
|
+
|
|
534
|
+
```
|
|
535
|
+
年发电量亿度 = 288000000 (~10⁸) ← label 说「亿」,裸数字已到 10⁸
|
|
536
|
+
⚠ 若按字面读成「亿」则为 2.88e16,请核对换算。
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
**3. 同批次一致性比对**(文档里说「这条能一次性拦住同一个错犯了四次」)
|
|
540
|
+
|
|
541
|
+
按 label 的量级词分组,组内 ≥2 条且量级一致、与该组声称的量级差**恰好一个数量级**时才报:
|
|
542
|
+
|
|
543
|
+
```
|
|
544
|
+
⚠ 本批有 4 条 label 含「万」(=10⁴),但结果全部落在 10³ 量级
|
|
545
|
+
量级与 label 声称的差 1 个数量级 —— 除数可能少除了一个 10
|
|
546
|
+
(例如该用 /1e10 却用了 /1e9)
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
**判据刻意保守**:差 0(口径已对齐,如 213 万吨)不报;差 ≥2(可能是正常的大数/小数)不报。
|
|
550
|
+
只报「差恰好一个数量级」——那正是「千吨被当成万吨」的特征。
|
|
551
|
+
|
|
552
|
+
**4. 「成功」改为分级语义**
|
|
553
|
+
|
|
554
|
+
文档原话:「『成功 7,失败 0』会让调用者跳过复核,因为『成功』两个字读起来像『对了』。」
|
|
555
|
+
|
|
556
|
+
```
|
|
557
|
+
算式全部求值成功(4 条,只表示算式无语法/符号错,不含结论正确性判断)
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
**5. terse 不许吞掉风险提示**
|
|
561
|
+
|
|
562
|
+
terse 的承诺是「省掉标题与统计」,不是省掉 ⚠。第一版把提示一起省了,
|
|
563
|
+
于是 terse 用户看到的是一行干净数字 —— 而干净正是最危险的。
|
|
564
|
+
|
|
565
|
+
新增 `test/guards.mjs`(23 项)。**第 4 节守「正确用例零误报」** ——
|
|
566
|
+
误报会让整条通道被关掉,比漏报更糟。反向对照已验证:撤掉防呆后 11 项变红。
|
|
567
|
+
|
|
568
|
+
### 新增(公式库 404 → 442:补齐电/光/核/化学计量的空白)
|
|
569
|
+
|
|
570
|
+
上一批补了 18 个量纲的**单位**,但公式库对其中 **8 个量纲完全空白** ——
|
|
571
|
+
有单位没公式,那批单位永远产出不出来:
|
|
572
|
+
|
|
573
|
+
| 量纲 | 补前 | 现在 |
|
|
574
|
+
|---|---|---|
|
|
575
|
+
| 磁通密度 T / 立体角 sr / 发光强度 cd / 照度 lx | 0 条 | 各有公式 |
|
|
576
|
+
| 放射性活度 Bq / 吸收剂量 Gy / 剂量当量 Sv / 催化活度 kat | 0 条 | 各有公式 |
|
|
577
|
+
|
|
578
|
+
新增 38 条,按组:
|
|
579
|
+
|
|
580
|
+
| 组 | 条数 | 代表 |
|
|
581
|
+
|---|---|---|
|
|
582
|
+
| **电学基础** | 11 | 欧姆定律(求电流/求电阻两式)、电功率 VI 式、并联电阻、电导倒数、Q=It、Q=CU、RC 时间常数、RC 放电、电感储能、LC 谐振 |
|
|
583
|
+
| **磁学**(原全空白) | 7 | 直导线磁场 μ0I/2πr、螺线管磁场、磁通量 BA、两导线安培力、法拉第通量变化式、螺线管电感、变压器电流比、功率因数 |
|
|
584
|
+
| **光学**(原全空白) | 6 | 圆锥立体角、照度平方反比、光通量 I·Ω、房间所需光通量、灯具功率按光效、照度=Φ/A |
|
|
585
|
+
| **核物理**(原全空白) | 8 | 衰变常数、活度 Nλ、**活度由质量**(复现「1 g 镭 = 3.7e10 Bq」)、吸收剂量 E/m、剂量当量 D·Q、剂量率、剩余比例 0.5ⁿ、半值层数 |
|
|
586
|
+
| **化学计量** | 5 | n=m/M、m=nM、酶活 U→kat、催化活度 Δn/t、摩尔浓度 |
|
|
587
|
+
|
|
588
|
+
**一个只在公式库才会踩的坑**:公式表达式的求值**不经过 evaluate 层的 `normalizeSource`**,
|
|
589
|
+
所以 `ln()` 不存在 —— mathjs 的 `log` 才是自然对数。
|
|
590
|
+
第一版半衰期公式写 `ln(2)/T`,三条全部报「没有名为 ln 的函数」,已改用 `log(2)`。
|
|
591
|
+
测试第 6 节专门守这条(扫全库不许出现 `ln(`)。
|
|
592
|
+
|
|
593
|
+
另外修了测试取值的一个坑:formula 的结果在 `value.answer`(**字符串**),
|
|
594
|
+
不是 `value.result` —— 取错会得到一堆 undefined,看着像"公式全坏"。
|
|
595
|
+
|
|
596
|
+
新增 `test/em-formulas.mjs`(43 项):第 2 节逐个确认「原先空白的 8 个量纲现在都有公式产出」,
|
|
597
|
+
第 8 节逐条实跑 38 条确认不崩。
|
|
598
|
+
|
|
599
|
+
### 新增(补齐 18 个量纲:电学 / 光学 / 化学 / 核物理)
|
|
600
|
+
|
|
601
|
+
原来单位表只有 **4 个 SI 基本单位**(m / kg / s / K),缺安培、摩尔、坎德拉 ——
|
|
602
|
+
于是**整个电学、光学、化学、核物理领域无法换算**:
|
|
603
|
+
写「十二伏电池」「三毫居里放射源」「0.5 戈瑞剂量」时工具一律不认识。
|
|
604
|
+
|
|
605
|
+
这一批把 7 个 SI 基本单位补全,并落地 22 个具名导出单位:
|
|
606
|
+
|
|
607
|
+
| 组 | 量纲(基准单位) |
|
|
608
|
+
|---|---|
|
|
609
|
+
| 电学(9) | 电流 A / 电荷量 C / 电压 V / 电容 F / 电阻 Ω / 电导 S / 磁通量 Wb / 磁通密度 T / 电感 H |
|
|
610
|
+
| 光学(4) | 立体角 sr / 发光强度 cd / 光通量 lm / 照度 lx |
|
|
611
|
+
| 化学与核物理(5) | 物质的量 mol / 放射性活度 Bq / 吸收剂量 Gy / 剂量当量 Sv / 催化活度 kat |
|
|
612
|
+
|
|
613
|
+
量纲总数 **14 → 32**,单位 **429 → 462**。
|
|
614
|
+
|
|
615
|
+
**两处刻意处理的坑**:
|
|
616
|
+
|
|
617
|
+
1. **`rad` 撞名**:辐射吸收剂量的 `rad`(1 rad = 0.01 Gy)与平面角弧度 `rad` 同名。
|
|
618
|
+
弧度已占用,所以辐射那条主名用 **`rad_dose`**,别名 `rad (dose)` ——
|
|
619
|
+
否则查 `rad` 永远命中角度,剂量永远换不出来。
|
|
620
|
+
2. **欧姆两个 Unicode 码位**:主名 `Ω`(U+03A9 希腊 Omega),别名必须同时收
|
|
621
|
+
**`Ω`(U+2126 欧姆符号)**。从不同来源粘贴的文字会带不同码位,
|
|
622
|
+
只收一个就有一半认不出。实测确认两个码位都能查到。
|
|
623
|
+
|
|
624
|
+
**常用非 SI 单位**:`Ah`/`mAh`(电池,归 measure)、`mV`/`kV`/`kΩ`/`MΩ`、
|
|
625
|
+
`gauss`(1 G = 10⁻⁴ T 精确)、`sphere`(4π sr)、`deg²`、`Ci`(3.7×10¹⁰ Bq 精确)、
|
|
626
|
+
`rad_dose`(0.01 Gy 精确)、`U`(酶单位 1.667×10⁻⁸ kat)、`mmol`/`µmol`/`nmol`。
|
|
627
|
+
|
|
628
|
+
溯源统一写进 note:BIPM SI Brochure 9th (2019) Table 2/3/5 为主,
|
|
629
|
+
非 SI 单位用 NIST SP 811 与 ISO 80000 系列。
|
|
630
|
+
|
|
631
|
+
新增 `test/si-units.mjs`(97 项):第 1–2 节守「32 量纲 + 18 个基准单位 factor=1」,
|
|
632
|
+
第 3 节守 rad 撞名,第 4 节守欧姆双码位,第 8 节守跨量纲必须被拒。
|
|
633
|
+
|
|
634
|
+
### 新增(中外古单位扩到 429 条,并把度量衡与科学单位分开)
|
|
635
|
+
|
|
636
|
+
上一版 287 条仍不够 —— 中国古制的细分单位与欧洲列强的传统单位几乎空白。
|
|
637
|
+
这一版补到 **429 条**,并且按用户要求**把两类分开**。
|
|
638
|
+
|
|
639
|
+
**分类**(新增 `UnitDef.category` 字段):
|
|
640
|
+
|
|
641
|
+
| 分类 | 条数 | 例子 | 谁会用 |
|
|
642
|
+
|---|---|---|---|
|
|
643
|
+
| **度量衡**(`measure`,默认) | 398 | 里/丈/斤/斗、俄尺/日尺/法磅、加仑/英亩、psi/节 | 写小说、算账、历史考据 |
|
|
644
|
+
| **科学**(`science`) | 31 | eV/里德伯/哈特雷、靶恩、玻尔半径、amu、erg、slug | 物理化学天文计算 |
|
|
645
|
+
|
|
646
|
+
判据是「**作者会不会在正文里写它**」:`psi` 会(工程题材)算度量衡;
|
|
647
|
+
`hartree` 不会算科学;`光年`/`AU` 会出现在科幻正文,**算度量衡**不算科学。
|
|
648
|
+
列表里分开显示(`度量衡 100 科学 7`),展开时度量衡在前、科学单位单独一段。
|
|
649
|
+
|
|
650
|
+
**新增覆盖**:
|
|
651
|
+
|
|
652
|
+
| 体系 | 代表 |
|
|
653
|
+
|---|---|
|
|
654
|
+
| 中国市制细分 | 尺寸分厘毫丝忽、石斗升合勺撮圭、担斤两钱分厘毫丝 |
|
|
655
|
+
| **中国历代** | 汉尺 23.1 cm、周尺 19.9 cm、清里 576 m、汉斤 258 g、清斤 596.8 g、库平两 37.3 g、漕平两、镒、铢、钧、咫 |
|
|
656
|
+
| **日本尺贯法** | 日尺 30.3 cm、间 1.82 m、日里 3.93 km、日升 1.8 L、贯 3.75 kg、匁 3.75 g、日斤 600 g、坪 3.31 m²、反 992 m²、鲸尺 37.9 cm |
|
|
657
|
+
| 俄制 | 沙绳 2.13 m、俄尺 71.1 cm、维尔肖克、俄磅 409.5 g、佐洛特尼克、维德罗 12.3 L、什托夫、恰尔卡 |
|
|
658
|
+
| 德制 | 莱茵尺 31.38 cm、鲁特、**德里 7.54 km**、德寸、德磅 467.6 g、德担、洛特、舍费尔、艾默 |
|
|
659
|
+
| 法制 | 法丈 1.949 m、法尺 32.5 cm、法寸、法分、法里、法磅 489.5 g、法担、布斯罗、塞蒂耶、米伊 |
|
|
660
|
+
| 西/葡/意/荷/北欧 | vara 83.6 cm、阿罗巴(西 11.5 kg vs 葡 14.7 kg)、braccio、voet、瑞典里 10.69 km、克拉夫特、波兰肘 |
|
|
661
|
+
| 印度/阿拉伯/奥斯曼 | 托拉 11.66 g、芒德 37.3 kg、坎迪、比加、dhira、farsakh、欧克 1.283 kg、奥斯曼尺 65 cm |
|
|
662
|
+
| 东南亚 | 泰尺、南洋担 60.5 kg、甘唐 |
|
|
663
|
+
|
|
664
|
+
**同字不同值是这批数据的核心价值**(写题材最容易出错):
|
|
665
|
+
|
|
666
|
+
| 名字 | 中国 | 日本 | 差 |
|
|
667
|
+
|---|---|---|---|
|
|
668
|
+
| 里 | 500 m | 3927 m | **7.9 倍** |
|
|
669
|
+
| 尺 | 32 cm | 30.3 cm | 5% |
|
|
670
|
+
| 斤 | 500 g | 600 g | 20% |
|
|
671
|
+
| 升 | 1 L | 1.80 L | 1.8 倍 |
|
|
672
|
+
| 亩 | 666.7 m² | 99.2 m² | 6.7 倍 |
|
|
673
|
+
|
|
674
|
+
**顺带补上公制基本单位的中文名**:`厘米`/`公分`、`毫米`/`公厘`、`微米`、`纳米`、`分米`、
|
|
675
|
+
`毫克`/`微克`/`纳克` —— 之前写「1 日尺 → 厘米」会报「不认识单位 cm」,
|
|
676
|
+
因为 `cm`/`mm` 根本没登记,只有别名 `厘米` 的说法也没有。
|
|
677
|
+
|
|
678
|
+
新增 `test/world-units.mjs`(106 项):每条断言都用**独立手算的期望值**,
|
|
679
|
+
因为历史单位的正确性无法靠直觉判断。第 9 节守「重名与重别名」(扩充最容易埋的雷),
|
|
680
|
+
第 10–11 节守分类。
|
|
681
|
+
|
|
682
|
+
### 新增(单位表扩充到 287 条,一切经公制中转)
|
|
683
|
+
|
|
684
|
+
从 88 条扩到 **287 条**,覆盖古今中外:
|
|
685
|
+
|
|
686
|
+
| 量纲 | 条数 | 代表 |
|
|
687
|
+
|---|---|---|
|
|
688
|
+
| 长度 | 48 | 里/丈/尺/寸/步/仞/寻/舍、英寻/码/英尺/英寸/弗隆、日里/町/尺、俄里、古希腊斯塔德、肘尺 |
|
|
689
|
+
| 质量 | 34 | 市斤/两/钱/担/铢/钧、长吨/短吨/英担/英石、金衡盎司/克拉、普特、日本斤/贯 |
|
|
690
|
+
| 体积 | 30 | 斗/市升/市合/斛、**美制 gal 与英制 gal_uk(差 20%)**、夸脱/品脱/液量盎司/茶匙/汤匙、石油桶、日本合/升/石(koku) |
|
|
691
|
+
| 能量 | 33 | 度电、卡/大卡、BTU/therm、吨油当量/吨煤当量、吨/千吨/百万吨 TNT、eV 系列、里德伯、foe |
|
|
692
|
+
| 功率 | 19 | **英制 hp 745.7 W 与公制 PS 735 W(差 1.4%)**、锅炉马力、制冷吨、人力/畜力、太阳光度 |
|
|
693
|
+
| 压强 | 19 | psi/ksi、mmHg/cmHg/Torr/inHg、米水柱、工程大气压、CGS 巴 |
|
|
694
|
+
| 面积 | 24 | 亩/顷、英亩/路德、日本町/反/坪/畳、barn |
|
|
695
|
+
| 时间 | 28 | 刻/时辰/更/炷香/盏茶/须臾/弹指/刹那/甲子、恒星日、银河年 |
|
|
696
|
+
| 速度 | 11 | 节、马赫(海平面/高空两套)、「日行百里」折算 |
|
|
697
|
+
| 温度 | 5 | °C/°F/K/兰氏/列氏 |
|
|
698
|
+
| **新增量纲** | 36 | 数据量(十进制 kB 与二进制 KiB)、角度(度/角分/角秒/密位)、力(N/kgf/lbf/kip)、频率(Hz/rpm/bpm) |
|
|
699
|
+
|
|
700
|
+
**「公制中转」的实现方式**:每个单位只声明「等于多少该量纲的公制基准单位」,
|
|
701
|
+
换算永远是 `value × 源factor ÷ 目标factor` 两步。于是任意两者都能互通 ——
|
|
702
|
+
测过 `1 日里 → 7.85 里`、`1 英寻 → 0.5715 丈`、`1 pood → 32.76 斤`、`1 gal_uk → 1.2 gal`。
|
|
703
|
+
|
|
704
|
+
**歧义处理**(这是最容易埋雷的地方):
|
|
705
|
+
|
|
706
|
+
- **加仑**:美制 3.785 L(`gal`)与英制 4.546 L(`gal_uk`)差 20%,两者都收,note 标明
|
|
707
|
+
- **吨**:公制 1000 kg、长吨 1016 kg、短吨 907 kg,三套都收
|
|
708
|
+
- **马力**:英制 745.7 W 与公制 735 W 差 1.4%,两者都收
|
|
709
|
+
- **「度」**:角度与电能两义,别名归角度,电能写 `度电` 或 `kWh`
|
|
710
|
+
- **日本与中国的同名单位**:日里 3.93 km vs 中国里 500 m(差 8 倍)、日升 1.8 L vs 市升 1 L,
|
|
711
|
+
都分开收并在 note 里点名差异
|
|
712
|
+
|
|
713
|
+
**列表输出改为「摘要 + 按量纲展开」**:287 条全量展开一次是 17000+ 字符,
|
|
714
|
+
而调用方通常只想确认「有没有我要的那条」。默认只给各量纲的计数与样例,
|
|
715
|
+
要看全表传 `unitScale:"length"`(也认中文名 `"长度"`)。
|
|
716
|
+
|
|
717
|
+
### 修复(注入提示词按频率重配字数)
|
|
718
|
+
|
|
719
|
+
注入内容是**每轮都付费**的固定成本。改版时发现三处真实问题:
|
|
720
|
+
|
|
721
|
+
1. **自相矛盾** —— 同时写着「输出默认全精度(几十位小数)」与「默认 8 位小数」,
|
|
722
|
+
两条并列下发,模型读到的是冲突指令。前者是过时表述,已删。
|
|
723
|
+
2. **比例失调** —— 世界推演独占 360 字符(44%),而它只对架空世界会话有用。
|
|
724
|
+
3. **高频缺口** —— 最常问的「该用哪个 operation」一句没写,能力清单却罗列 12 类。
|
|
725
|
+
|
|
726
|
+
新的分配(brief 档,757 字符,原 817):
|
|
727
|
+
|
|
728
|
+
| 内容 | 频率 | 字数 |
|
|
729
|
+
|---|---|---|
|
|
730
|
+
| 行为约束(必须调用/不要心算) | 每轮 | 33 |
|
|
731
|
+
| **选哪个 operation** | 极高 | 209 |
|
|
732
|
+
| 可信度标签怎么读 | 中 | 120 |
|
|
733
|
+
| 精度两层 | 中 | 107 |
|
|
734
|
+
| 世界推演分工 | 低 | 120 |
|
|
735
|
+
|
|
736
|
+
能力全清单不再进 brief —— schema 的 enum 与 help 里都有,重复下发是同一份信息付两次钱。
|
|
737
|
+
|
|
738
|
+
新增 `test/prompt-budget.mjs`(23 项)守这条:高频段必须是最长的段、
|
|
739
|
+
低频段压到 120 字符内、不许出现矛盾表述、关键行为约束不许砍。
|
|
740
|
+
|
|
741
|
+
### 修复(多步计算:失败步骤的下游曾静默变「虚成功」)
|
|
742
|
+
|
|
743
|
+
批量内按书写顺序执行、前一条赋值对后一条可见 —— 这条路本身是好的。
|
|
744
|
+
但**一个依赖失败步骤的下游**曾经不算失败,而是被 mathjs 当成「2 b(单位)」
|
|
745
|
+
算出一个合法结果,批量汇总里显示为**成功**:
|
|
746
|
+
|
|
747
|
+
```
|
|
748
|
+
{expressions:["a=5","b=oops*2","d=b*2"]}
|
|
749
|
+
修复前 d=b*2 = 2 b ← 合法单位结果,汇总「成功 2,失败 1」
|
|
750
|
+
修复后 d=b*2 → 失败[unknown_symbol],汇总「成功 1,失败 2」
|
|
751
|
+
```
|
|
752
|
+
|
|
753
|
+
根因是**两个独立缺陷叠在一起**:
|
|
754
|
+
|
|
755
|
+
1. **单位判据只看「同级有没有数字」,不看顺序**。
|
|
756
|
+
mathjs 保留书写顺序:`2 b` 是 `[数字, 符号]`(单位),`b*2` 是 `[符号, 数字]`(变量)。
|
|
757
|
+
旧判据一律放过,于是 `b*2` 被当成单位。
|
|
758
|
+
|
|
759
|
+
2. **赋值语句的右半部分挂在 `value` 上,而 AST 遍历只走 `args/items/content/object/index`**。
|
|
760
|
+
`d=b*2` 的 AST 是 `AssignmentNode(name=d, value=OperatorNode(*))`,
|
|
761
|
+
赋值右侧**整个不被判据看到** —— 所以第 1 条即使修好了也不生效。
|
|
762
|
+
|
|
763
|
+
这类「下游悄悄变成虚成功」比报错难发现得多:批量汇总里它算成功,
|
|
764
|
+
而结果是 `2 b` 这种看着完全正常的量。
|
|
765
|
+
|
|
766
|
+
新增 `test/multistep.mjs`(26 项):第 3 节专守这条;第 5 节用 9 种真单位写法
|
|
767
|
+
守「修复不能误伤单位」(`5 V`、`9.81 m/s^2`、`s^2`、`(2+3) V`、`1/2 h` 等)。
|
|
768
|
+
|
|
769
|
+
### 新增(工作区命名变量,默认关闭)
|
|
770
|
+
|
|
771
|
+
工作区的 `variables` 字段、写入(`workspaceVariables`)、删除(`remove-variable`)、
|
|
772
|
+
显示(`show`)**本来都已存在**,唯独**读取路径缺失** —— 存进去的变量在计算里用不到:
|
|
773
|
+
|
|
774
|
+
```
|
|
775
|
+
{action2:"set", workspaceVariables:{BTU_LB:1260000}} → 变量 1 个 ✓ 存住了
|
|
776
|
+
{expression:"BTU_LB/1000"} → Undefined symbol ✗ 用不了
|
|
777
|
+
```
|
|
778
|
+
|
|
779
|
+
「能删不能加、加了用不了」是设计不一致,这一版把最后一环接上:
|
|
780
|
+
|
|
781
|
+
```
|
|
782
|
+
workspace set useWorkspaceVariables:true → 打开开关(逐工作区)
|
|
783
|
+
evaluate BTU_LB/1000 → 1260
|
|
784
|
+
evaluate variables:{BTU_LB:999000} → 本次参数优先,得 999
|
|
785
|
+
```
|
|
786
|
+
|
|
787
|
+
**默认关闭**。打开后同一表达式在不同工作区状态下结果可能不同,
|
|
788
|
+
会削弱「同输入同输出」——那是本项目做 hash 复现与回归对比的基础,
|
|
789
|
+
所以它是一个显式的、逐工作区的选择,不默认生效。
|
|
790
|
+
关闭时行为与未引入该功能时**完全一致**(变量仍存着,能看能删)。
|
|
791
|
+
|
|
792
|
+
**缓存必须跟着变量走**:缓存键原本只含工作区名与常数指纹,不含变量内容。
|
|
793
|
+
若不修,`改变量 → 再算 → 命中旧缓存 → 静默返回改之前的数`——
|
|
794
|
+
与文档批评过的「改常数后返回旧值」是同一类。现在变量内容进指纹:
|
|
795
|
+
|
|
796
|
+
```
|
|
797
|
+
改前 BTU_LB=1260000 → 1260
|
|
798
|
+
改后 BTU_LB=1055000 → 1055 ← 不是命中旧缓存的 1260
|
|
799
|
+
```
|
|
800
|
+
|
|
801
|
+
顺带把 `workspaceVariables` 与 `useWorkspaceVariables` 补进工具 schema:
|
|
802
|
+
前者此前代码支持但参数表里没有(模型看不见),属同批「可发现性」问题。
|
|
803
|
+
|
|
804
|
+
### 说明(工作区变量)
|
|
805
|
+
|
|
806
|
+
- 新增 `test/workspace-variables.mjs`(18 项),其中第 3 节专守「改变量后缓存必须失效」。
|
|
807
|
+
第 5 节守「关掉开关完全回到旧行为」,第 6 节守「开关逐工作区、不串区」。
|
|
808
|
+
|
|
809
|
+
### 说明(第二轮)
|
|
810
|
+
|
|
811
|
+
- 新增测试套件 `test/arg-guard.mjs`(41 项),守上面四条:
|
|
812
|
+
未知参数必须报错、文档提过但没做的参数不能假装做了、
|
|
813
|
+
`displayPrecision:0` 生效、括号错给位置、英制单位可换算、help 不超预算。
|
|
814
|
+
- 测试总数 81 套 / 3859 项 → **82 套 / 3900 项**。
|
|
815
|
+
|
|
816
|
+
### 说明
|
|
817
|
+
|
|
818
|
+
- **测试路径 ≠ 真实调用路径**:2.1.0 曾因此出现过「77 套全绿而工具实际不可用」。
|
|
819
|
+
`test/integration.mjs` 里的输出字段声明守卫继续守这条:新增字段若没进 `output.schema`,
|
|
820
|
+
这条会红。
|
|
821
|
+
|
|
822
|
+
### 修复(按 2026-11-07 实测报告《使用问题与改进建议》)
|
|
823
|
+
|
|
824
|
+
这份报告的落点是一句话:「工具把安全性放在了错误的位置 —— 它校验「式子能不能算」,
|
|
825
|
+
却不校验「结果对不对」。」其中六条已修,另有一条是本轮实测发现、报告未提的回归。
|
|
826
|
+
|
|
827
|
+
- **单条与批量对「非有限值」的判断不一致**(报告最核心的一条)。
|
|
828
|
+
|
|
829
|
+
```
|
|
830
|
+
{expression:"1/0"} → 错误[non_finite] ✓
|
|
831
|
+
{expressions:["1+1","1/0","sqrt(-1)","log(0)"]} → 「算式全部求值成功(4 条)」 ✗
|
|
832
|
+
```
|
|
833
|
+
|
|
834
|
+
同一个式子换个调用方式就从「错」变成「对」,而批量恰恰是 AI 最常用的形态。
|
|
835
|
+
现在批量里非有限值归入 `failed`:`ok=false` + `partial=true` + `failed=N`。
|
|
836
|
+
|
|
837
|
+
新增 `isNonFiniteValue`(下钻到 `Unit.value`):`(1/0)*2 kg` 序列化成
|
|
838
|
+
`"Infinity g"`,旧的 `containsNonFinite` 只认恰好 `"Infinity"`,于是带单位的
|
|
839
|
+
非有限值连**单条**都拦不住 —— 而它看起来像个正经结果。
|
|
840
|
+
反向守:`1e400`、`2^1024` 这类**有限的极大数**不误判(转双精度才溢出,
|
|
841
|
+
BigNumber 自己知道自己是有限的)。
|
|
842
|
+
|
|
843
|
+
- **写出来的目标单位被输出层悄悄撤回**(本轮实测发现,报告未提)。
|
|
844
|
+
|
|
845
|
+
```
|
|
846
|
+
2 m to cm → mathjs 算出 200 cm → 工具输出 "2 m"
|
|
847
|
+
1 t to kg → mathjs 算出 1000 kg → 工具输出 "1 t"
|
|
848
|
+
```
|
|
849
|
+
|
|
850
|
+
根因是单位归位只看 `unit.value`、不看调用方意图,把**显式换算的目标**按阶梯
|
|
851
|
+
重挑了一遍,恰好挑回出发点。数字看着完全合法(`2 m` 是正经长度),所以没人怀疑。
|
|
852
|
+
修法:表达式里有 `to` / `.to()` 时跳过归位。
|
|
853
|
+
|
|
854
|
+
顺带补上被它掩盖的另一半:显式换算时小数位没走 `displayPrecision`,
|
|
855
|
+
`5 cm to inch` 会吐 21 位小数。
|
|
856
|
+
|
|
857
|
+
- **`to` 的报错从 `internal` 降级为可行动的提示**。
|
|
858
|
+
|
|
859
|
+
`internal` 在本项目的约定里意思是「工具自己坏了」,会让人去重试;
|
|
860
|
+
而真实原因有四类、修法各不相同。现在分开:
|
|
861
|
+
`unit_name_conflict`(`1 s to min` —— min 在 mathjs 里是函数不是单位,写 minute)、
|
|
862
|
+
`not_a_quantity`(`0.5 to kW` —— 裸数字没有单位可换,该用 operation="units")。
|
|
863
|
+
|
|
864
|
+
- **`evaluate` 与 `units` 两套单位表打通**。
|
|
865
|
+
|
|
866
|
+
`mph` / `kn` / `rpm` / `inHg` / `cal` / `gauss` / `slug` / `shortton` 等
|
|
867
|
+
在 `units` 里认得、在 `evaluate` 里报 `Undefined symbol`。表不通就逼人**手填系数**
|
|
868
|
+
(`10*745.7`),而手填系数正是报告那四起千倍级事故的共同源头。
|
|
869
|
+
|
|
870
|
+
做法是在 `buildMath` 里注入 174 个单位,注入完照旧删掉 `createUnit` ——
|
|
871
|
+
**安全边界一点没动**,只是把「我们自己能定义单位」用上了。三条取舍:
|
|
872
|
+
不覆盖既有单位、不收单字母(否则吃掉变量 `c`/`G`)、不覆盖函数名。
|
|
873
|
+
|
|
874
|
+
**踩到一个很隐蔽的连带污染**:注入会把新单位登记进 mathjs 的全局
|
|
875
|
+
`currentUnitSystem`,而 `Unit.toString()` 的 `simplify()` 从那里挑**第一个**
|
|
876
|
+
同维度单位,于是 `1 m^2` 变成 `0.0149 katha`、`1 m^3` 变成 `1086 gantang`。
|
|
877
|
+
最阴的是:注入的用例全绿,坏的是**别的**老用例 —— 只有跑全量回归才看得见。
|
|
878
|
+
修法:注入后把 unitSystem 重置到 `si`(实测两者输出原本一致,且 `si` 是只读的)。
|
|
879
|
+
|
|
880
|
+
- **文档把「带单位写」提到最前**(报告 P0-1)。
|
|
881
|
+
|
|
882
|
+
工具描述加两行(净压到 414/450 字符),`help` 里把 `5 cm to inch`
|
|
883
|
+
从第 4 个例子提到第 1 个,并写明裸数字的风险;补上 `expressions` 元素的
|
|
884
|
+
`{label, expr}` 对象写法,以及「`标签=表达式` 不支持」这条必然踩的坑。
|
|
885
|
+
|
|
886
|
+
- 新增测试套件 `test/report-1107.mjs`(63 项),每条修复都带反向对照:
|
|
887
|
+
未写单位仍须归位、复数不算非有限、有限大数不误判、既有单位不被改写。
|
|
888
|
+
|
|
889
|
+
### 变更(帮助系统改成分节目录)
|
|
890
|
+
|
|
891
|
+
旧的 `help` 是一整块 **5900 字符**的摊平清单,每次调用都付全量成本。分段统计:
|
|
892
|
+
|
|
893
|
+
```
|
|
894
|
+
世界观推演 3039 字符 ← 占 52%,但算一条 1/3 也要读它
|
|
895
|
+
求值与代数 612
|
|
896
|
+
数据管理 557
|
|
897
|
+
公式库 337
|
|
898
|
+
其余各节合计 700 左右
|
|
899
|
+
```
|
|
900
|
+
|
|
901
|
+
改为三层结构:
|
|
902
|
+
|
|
903
|
+
```
|
|
904
|
+
operation:"help" → 目录(12 节,各带一句话简介)
|
|
905
|
+
operation:"help", helpTopic:"world" → 该节完整正文
|
|
906
|
+
正文内部再分层 → 字段表 / 默认值 / 常见坑
|
|
907
|
+
```
|
|
908
|
+
|
|
909
|
+
实测:目录 **1731 字符**,单节 203—1904、平均约 810(全量的 14%)。
|
|
910
|
+
|
|
911
|
+
**两个互相对抗的要求同时守住** —— 省过头就是「AI 不知道有这个功能」,那比不拆更糟:
|
|
912
|
+
|
|
913
|
+
1. **目录必须可发现**:每节简介要说清「解决什么问题」(测试断言 ≥15 字),
|
|
914
|
+
并配别名 —— AI 不知道 key 叫 `linalg`,但会说「矩阵」;写「星球」也查得到 `world`。
|
|
915
|
+
2. **内容不许因拆而缩水**:旧版为压 6000 字符上限砍掉了 world 的默认值、
|
|
916
|
+
derivation 的子命令参数、错误码表。现在每节按需付费,所以**补全了** ——
|
|
917
|
+
`world` 节 25 个字段带默认值与单位,29 个 derivation 子命令逐个说明,
|
|
918
|
+
并新增错误码对照表。
|
|
919
|
+
|
|
920
|
+
工具描述改成指引这两步(不写的话 AI 会以为 help 只给目录,或者干脆不查,
|
|
921
|
+
那分节就等于把功能藏起来了)。未知节名**不报错** —— 回目录并点名:
|
|
922
|
+
「报错会打断探索,而目录能让它自己纠偏」;大小写、空格、换行都容忍。
|
|
923
|
+
|
|
924
|
+
新增 `test/help-topics.mjs`(63 项)守这两条拉扯。既有 9 处依赖 help 全文的断言
|
|
925
|
+
改为按节取用 —— 断言目的没变(说明必须仍能找到),只是找的位置变了。
|
|
926
|
+
## [2.1.1] — 2026-10-28
|
|
927
|
+
|
|
928
|
+
紧急修复 **2.1.0 会让工具不可用**的问题。
|
|
929
|
+
|
|
930
|
+
### 修复
|
|
931
|
+
|
|
932
|
+
- **`notice` / `cached` 未在输出 schema 声明,导致调用失败**。
|
|
933
|
+
|
|
934
|
+
宿主用 `additionalProperties: false` **校验**工具输出。2.1.0 的代码会产出
|
|
935
|
+
`notice`(显示精度提示、精度不足提醒)与 `cached`(缓存命中标记),
|
|
936
|
+
但 `OUTPUT_SCHEMA` 里没有声明这两个字段,于是宿主拒绝整次调用:
|
|
937
|
+
|
|
938
|
+
```
|
|
939
|
+
Error: tool "math_execute" returned invalid output:
|
|
940
|
+
"value.notice" is not a declared property (additionalProperties: false)
|
|
941
|
+
```
|
|
942
|
+
|
|
943
|
+
触发条件是**任何带小数的结果**(默认 8 位小数下几乎每次都会产出 notice),
|
|
944
|
+
也就是说 2.1.0 装上去基本不能用。
|
|
945
|
+
|
|
946
|
+
**为什么单元测试没发现**:测试直接调 `runMathTool`,拿到的是普通对象,
|
|
947
|
+
不经过宿主那层 schema 校验 —— 77 套全绿,而真实宿主一调就废。
|
|
948
|
+
这是「测试走的路径与真实调用路径不同」的典型盲区。
|
|
949
|
+
|
|
950
|
+
### 新增
|
|
951
|
+
|
|
952
|
+
- **输出字段声明守卫**(`test/integration.mjs`):断言 `MathResult` 能产出的
|
|
953
|
+
每个字段都已在 `output.schema` 声明,并实跑一次会产出 `notice` 与 `cached`
|
|
954
|
+
的调用。以后再加字段忘了声明,这条会红。
|
|
955
|
+
|
|
5
956
|
## [2.1.0] — 2026-10-28
|
|
6
957
|
|
|
7
958
|
公式库扩到 404 条、新增天体目录与类型学、工具定义瘦身 21%,并把「计算精度」与
|