dsh-vibe-math 2.3.1 → 2.3.3
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/AUDIT-CHECKLIST.md +59 -0
- package/README.md +16 -6
- package/RELEASE-NOTES-2.3.2.md +145 -0
- package/RELEASE-NOTES-2.3.3.md +115 -0
- package/audit-formal-sensitivity.mjs +11 -2
- package/audit-prompt-invariants.mjs +459 -0
- package/audit-spec-traceability.mjs +193 -0
- package/docs/formal-verification.md +37 -13
- package/docs/generate_framework_diagram_v5.mjs +2 -1
- package/docs/test-timing.md +32 -10
- package/formal-verify-v2.test.mjs +288 -2
- package/formal-verify-v3.test.mjs +230 -4
- package/formal-verify-v4.test.mjs +205 -5
- package/formal-verify-v5.test.mjs +114 -4
- package/installer.js +3 -1
- package/package.json +6 -2
- package/prompt-corpus-persona/persona-corpus.json +2 -2
- package/prompt-corpus-persona/persona-corpus.md +6 -2
- package/prompt-corpus-v2/formal-verify-v2.json +164 -44
- package/prompt-corpus-v2/formal-verify-v2.md +1374 -44
- package/prompt-corpus-v3/formal-verify-v3.json +236 -128
- package/prompt-corpus-v3/formal-verify-v3.md +1509 -400
- package/prompt-corpus-v4/formal-verify-v4.json +8 -3
- package/prompt-corpus-v4/formal-verify-v4.md +38 -10
- package/prompt-corpus-v5/prompt-corpus-v5.json +175 -246
- package/prompt-corpus-v5/prompt-corpus-v5.md +341 -781
- package/prompt-v5-integrity.test.mjs +136 -22
- package/run-tests.mjs +30 -11
- package/vibe-math-v2/vibe-math-v2.js +163 -38
- package/vibe-math-v2//345/256/236/347/216/260/346/226/271/346/241/210.md +58 -6
- package/vibe-math-v3/vibe-math-v3.js +95 -25
- package/vibe-math-v3//345/256/236/347/216/260/346/226/271/346/241/210.md +8 -7
- package/vibe-math-v4/vibe-math-v4.js +103 -24
- package/vibe-math-v4//345/256/236/347/216/260/346/226/271/346/241/210.md +37 -14
- package/vibe-math-v5/agent.cordis.yml +6 -2
- package/vibe-math-v5/vibe-math-v5.js +56 -10
- package/vibe-math-v5//345/256/236/347/216/260/346/226/271/346/241/210.md +45 -14
- package/vibe-math-v5//346/236/266/346/236/204/345/233/276.md +16 -2
- package//347/244/272/344/276/213/345/233/276//346/241/206/346/236/266/345/233/276-v5.svg +6 -5
package/AUDIT-CHECKLIST.md
CHANGED
|
@@ -119,6 +119,55 @@
|
|
|
119
119
|
- [ ] 每个档位(`off` / `encourage` / `require`)的注入文本是否**各自**被人读过?只读一个档位等于没读
|
|
120
120
|
——首版 `require` 档的门禁措辞从未进入任何语料。
|
|
121
121
|
|
|
122
|
+
### 1.8 四套同构:任何语义修正必须**四套同步**
|
|
123
|
+
|
|
124
|
+
v2/v3/v4/v5 是**同构实现**(同一份契约、四份独立代码,刻意零共享)。这带来一个特有的缺陷类别:
|
|
125
|
+
**修正只落到一套**。真实事故(2.3.1 → 2.3.2):
|
|
126
|
+
|
|
127
|
+
- `defect` 的"`encourage` 档不得声称框架会强制搁置"这条修正只改了 v5,另外三套仍无条件宣称
|
|
128
|
+
"本次裁定**不定论**"——承诺了 `encourage` 档根本无法强制的行为;
|
|
129
|
+
- "撤回归档证明"在 v5 是**删除 → 校验真的没了 → 否则覆盖撤回说明**,另外三套只做尽力删除
|
|
130
|
+
(两套静默吞掉失败、一套不校验)——宿主删不掉时,已撤回的证明仍留在 `Verified/Lean/<id>.lean`
|
|
131
|
+
这个"大家找证明"的位置;
|
|
132
|
+
- `formal` 回执通道在 v2/v3 有 `formalOn()` 守卫,v4/v5 没有——`off` 档可被残留回执写入状态。
|
|
133
|
+
- **「随手一次动作不得撤销已成立的证明」这条规则在四套里各写了一遍,却只在一套里被断言过**(v4 的
|
|
134
|
+
`formalSetRun`):确认轮实测发现 v2 的 `used` **回执**通道无条件降级 `passed`(同一条规则的另一条
|
|
135
|
+
路径),v3 只保留 `passed` 而把 `blocked` 打回 `attempted`(门禁被重新关上)。同一语义在**多条路径**
|
|
136
|
+
上要逐条核对:工具路径、回执路径、归档路径各自独立。
|
|
137
|
+
|
|
138
|
+
所以:
|
|
139
|
+
|
|
140
|
+
- [ ] 任何语义/措辞修正,**逐一核对四套**(含各自的 `实现方案.md`、persona、语料与断言);
|
|
141
|
+
- [ ] 参数、工具名、字段名、路径、错误码这类**表面**已有静态守卫
|
|
142
|
+
(`audit-persona-surface` / `audit-spec-traceability` / `audit-prompt-invariants`);
|
|
143
|
+
但**语义**(承诺强度、失败回退、边界条件)没有静态守卫,必须靠"把四套**渲染后的提示词/行为**
|
|
144
|
+
并排对照"来查——随包语料就是为这个准备的;
|
|
145
|
+
- [ ] 用**同一份输入**驱动四套,比较**可观测结果**(记录落库、文件是否撤回、门禁是否放行),
|
|
146
|
+
而不是比较代码长得像不像。
|
|
147
|
+
|
|
148
|
+
### 1.9 工具参数 schema:文档写了 ≠ 工具收得下
|
|
149
|
+
|
|
150
|
+
§1.6 查的是"persona 里有没有写",这一节查**工具的参数 schema 收不收得下**。本仓库所有工具 schema 都由
|
|
151
|
+
`objParams` 收口,并以 `additionalProperties:false` **关闭**:schema 没列出的键会被任何遵守 schema 的
|
|
152
|
+
provider **直接拒绝**。于是"提示词/规格/状态表都写着这个参数"完全可以在**功能根本打不开**的同时全绿。
|
|
153
|
+
|
|
154
|
+
- [ ] 每个"可调参数"是否同时出现在:**设置工具的参数 schema**、发现面(`vibe_math_setup` 返回的
|
|
155
|
+
`PARAM_SCHEMA` / v4·v5 的 status 参数表)、`<vibe root>/*setting.json` 模板、以及 persona 参数表?
|
|
156
|
+
**真实事故(2.3.2 D1)**:v3 的四个 Lean 参数写进了 persona、规格与状态行,却**从未写进
|
|
157
|
+
`vibe_math_set_params` 的 schema**;所有套件全绿(套件直接调 handler、绕过 schema),而用户
|
|
158
|
+
**永远无法开启这个功能**。
|
|
159
|
+
- [ ] schema **声明的**每个键,参数层是否**真的接收**?(v2/v3 的闸门是 `DEFAULT_PARAMS` 的键集、
|
|
160
|
+
v4 是 `k in params`、v5 是 `normalizeParams` 的类型列表。)声明而不接收 = 调用返回 `{ok:true}`、
|
|
161
|
+
什么都不发生——最容易被读成"设置成功"的静默失效。
|
|
162
|
+
- [ ] 同一工具被**注册两次**(v2/v3 各有"会话 handler 表"与"真实 `tools.register`"两份定义)时,
|
|
163
|
+
两份 schema 是否**逐键一致**?漂移会让其中一条路径上的功能不可达。
|
|
164
|
+
- [ ] 新增/修改任何参数后,跑 `node audit-prompt-invariants.mjs`(I13/I14)与
|
|
165
|
+
`node audit-prompt-invariants.mjs --self-probe`(证明这两条不变式**真的会变红**)。
|
|
166
|
+
|
|
167
|
+
> **守卫为什么必须是"可被证伪的"**:I13/I14 用 `--self-probe` 在内存里注入真实缺陷形状
|
|
168
|
+
> (v3 少一个 Lean 参数 / v4 多一个参数层不接收的键 / v5 的 `normalizeParams` 少一项),
|
|
169
|
+
> 要求对应不变式**变红**,并要求**未变异的对照跑仍为绿**。没有对照的探针会把"脚本坏了"当成"守住了"。
|
|
170
|
+
|
|
122
171
|
---
|
|
123
172
|
|
|
124
173
|
### 2.1 逐条断言,而不是抽查
|
|
@@ -209,8 +258,18 @@
|
|
|
209
258
|
[`docs/test-timing.md`](docs/test-timing.md)。若某个套件远慢于基线,先查它是否在等一个
|
|
210
259
|
**永远不会发生的条件**(真实事故:v2 套件 186 s,主因是一次 `tick(1100)` 嵌在
|
|
211
260
|
"从不提前退出"的 16 次循环里)。
|
|
261
|
+
- [ ] **产物是异步写出来的**:驱动循环("安静即停")可能在框架把卡片/状态文件落盘之前就退出,
|
|
262
|
+
而 `assert(existsSync(f))` **不会抛**、紧随其后的 `readFileSync(f)` 会抛 `ENOENT` —— 一次抖动
|
|
263
|
+
就变成**未捕获异常**,整个套件中止、后面所有断言全部丢失(真实事故:并行跑时
|
|
264
|
+
`e2e-v4-fixes` 崩在 `Verified/命题/m-meth.md`,12 个用例只跑了 2 个)。写法:
|
|
265
|
+
先 `await waitFor(()=>existsSync(f), 3000)`,再用**防御性读**(`try{…}catch{return ''}`)
|
|
266
|
+
——缺文件必须是**一条干净的断言失败**,绝不能是崩溃。参见该套件里的 `readArtifact`。
|
|
212
267
|
- [ ] 发布产物自证:不是"publish 退出 0"就算完成——要从 registry 取回 tarball,
|
|
213
268
|
核对 shasum、逐字节比对插件、确认修复标记存在、并在**已发布包内**跑一遍套件。
|
|
269
|
+
- [ ] **发布元数据交给序列化器**:不要用字符串替换手写 `package.json` 的字段(`compatNote` 里一个
|
|
270
|
+
ASCII 双引号就能产出非法 JSON;`\\u0000` 之类转义在单引号字符串里会变成真控制字符)。
|
|
271
|
+
正确写法是 `JSON.parse` → 改属性 → `JSON.stringify(pkg, null, 2)`,写完再 `JSON.parse` 复核
|
|
272
|
+
并扫描控制字符。
|
|
214
273
|
|
|
215
274
|
---
|
|
216
275
|
|
package/README.md
CHANGED
|
@@ -247,7 +247,7 @@ flowchart TB
|
|
|
247
247
|
|
|
248
248
|
| 取值 | 含义 |
|
|
249
249
|
|---|---|
|
|
250
|
-
| **`'off'`(默认)** | **不额外进行任何要求。**
|
|
250
|
+
| **`'off'`(默认)** | **不额外进行任何要求。** 成员提示词里不出现任何 Lean 内容,不写入任何形式化状态,验证流程与门禁完全不变(是**真正的无操作**,有断言与探针守着)。三个工具仍注册可用(主动调用照常工作);主代理的 persona **始终**写着这三个工具与四个参数——否则这个开关就不可发现、"off" 也就无从打开 |
|
|
251
251
|
| `'encourage'` | **鼓励但不强制**:验证时先判断该对象的**实现难度**,能在可接受工作量内形式化就优先做;一旦 Lean 通过,审查重心转为**忠实性**。平时工作也鼓励把常用/可能复用的对象、假设、新定义随手形式化归档。**不设门禁** |
|
|
252
252
|
| `'require'` | **强制**:真/假结论必须满足「**Lean 已通过**」或「**显式记录了阻塞原因**」,否则本次裁定**不生效**——记为未定论(原因 `formal-required`)、写入「形式化待办」、群聊公告,对象留库待形式化后重新提议 |
|
|
253
253
|
|
|
@@ -265,14 +265,22 @@ Lean 通过只保证"这段代码过了内核",**不保证它说的就是命
|
|
|
265
265
|
用来求真的机制反而**伪造出一个错误的否定结论**。
|
|
266
266
|
- 正确做法:给一个严格介于 0 与 1 之间的值(记为弃权)+ 用回执
|
|
267
267
|
`formal:{decision:'defect', note:'<具体偏差>'}` 记录偏差。框架随即**撤回这条证明的「已通过」状态**
|
|
268
|
-
(降级为 `attempted
|
|
269
|
-
|
|
268
|
+
(降级为 `attempted`;`Verified/Lean/<id>.lean` **删除**,宿主删不掉时改写为"已撤回"说明,
|
|
269
|
+
绝不把一个已撤回的证明留在大家找证明的位置;写入「形式化待办」),`require` 档下
|
|
270
|
+
**本次裁定不定论**(`encourage` 档没有门禁,不得声称框架会强制搁置——那里靠表决者弃权阻止定论);
|
|
271
|
+
修正形式化并重新跑通后再投票。
|
|
270
272
|
- 只有表决者**独立于这份 Lean 代码**也能确定命题为假(并能给出独立理由)时才投 0。
|
|
271
273
|
|
|
274
|
+
> **回执通道**(不调用 Lean 工具的成员也能留下判断,`require` 档下必须留):
|
|
275
|
+
> `"formal": {"target":"<对象id>", "decision":"used|blocked|defect", "file":"Formal/<对象id>.lean", "note":"难度判断/阻塞原因/具体偏差"}`。
|
|
276
|
+
> `decision='blocked'`/`'defect'` 时 **`note` 必填**(缺则整条拒绝);`used` 只把对象记为 `attempted`;
|
|
277
|
+
> `off` 档下这个通道**失效**(否则 `off` 就不是真正的无操作了)。
|
|
278
|
+
|
|
272
279
|
> 注入提示词的另外三条硬要求(契约 §6):工具名一律**全称**(`<prefix>lean_archive` 不是
|
|
273
280
|
> `lean_archive`——缩写不是注册名,代理照抄会调用一个不存在的工具);归档可复用定义/引理**前先跑通**,
|
|
274
|
-
> 跑不通不许进库;**工具链缺失**(`LEAN_NOT_FOUND
|
|
275
|
-
> "宿主无 Lean 工具链"
|
|
281
|
+
> 跑不通不许进库;**工具链缺失**(`LEAN_NOT_FOUND` 解析不到可执行文件 / `NO_SUBPROCESS` 宿主没有
|
|
282
|
+
> subprocess 服务)时把代码写下来归档并在 `note` 写明"宿主无 Lean 工具链"——这算显式阻塞原因,
|
|
283
|
+
> 门禁据此放行,不会因为装不了 Lean 而卡死。
|
|
276
284
|
|
|
277
285
|
### 归档:形式化代码放哪里
|
|
278
286
|
|
|
@@ -808,7 +816,9 @@ v5 的完整架构(含成员生命周期、一轮时序、共识状态机、
|
|
|
808
816
|
- **Lean 形式化验证(四架构共用契约)**:[`docs/formal-verification.md`](docs/formal-verification.md)
|
|
809
817
|
- **测试耗时基线与并行跑法**:[`docs/test-timing.md`](docs/test-timing.md)(`node run-tests.mjs` 并行跑全部套件 ≈1.9 min;探针脚本 ≈2.6 min;每个 runner 都会打印耗时/加速比供下次选策略)
|
|
810
818
|
- **静态提示词面一致性(persona ↔ 工具注册表 ↔ 斜杠命令 hint/usage)**:[`audit-persona-surface.test.mjs`](audit-persona-surface.test.mjs)(197 条断言,并生成 [`prompt-corpus-persona/persona-corpus.md`](prompt-corpus-persona/persona-corpus.md) 供人工复核)+ [`audit-persona-sensitivity.mjs`](audit-persona-sensitivity.mjs)(11 条灵敏度探针)——守"注册的工具必须在 persona 里出现 / persona 里的名字必须真的注册 / `prefix` 与 `text` 两块逐行一致 / hint、usage、实际分支三处必须一致"
|
|
811
|
-
- **全面检查必查清单**:[`AUDIT-CHECKLIST.md`](AUDIT-CHECKLIST.md)
|
|
819
|
+
- **全面检查必查清单**:[`AUDIT-CHECKLIST.md`](AUDIT-CHECKLIST.md)(本仓库的强制审计流程;§1.9 专门查"工具参数 schema 收不收得下")
|
|
820
|
+
- **提示词/交互不变式(四套一起,可一键复核)**:[`audit-prompt-invariants.mjs`](audit-prompt-invariants.mjs)(151 条断言)——把"历史上真实发生过的提示词/工具面缺陷类别"逐条编码成静态不变式(缩写工具名、把忠实性缺陷投成 0、`defect` 只写在提示词里没实现、回执契约缺 `defect`、无 note 放行、字段名错、`off` 档回执仍能写状态、语料不确定、探针缺失、**工具的封闭 schema 收不下它自己文档里的参数**、**schema 声明了参数层却静默丢弃的键**)。加 `--self-probe` 会在内存里注入这些缺陷形状,要求对应不变式**变红**、未变异的对照跑**仍为绿**(5/5);脚本自身另带 X5–X7 三条自检(注释扫描器必须认正则字面量、字符串里的 `//` 必须保留、抹注释不改变行结构)
|
|
821
|
+
- **规格 ↔ 代码可追溯(四套一起)**:[`audit-spec-traceability.mjs`](audit-spec-traceability.mjs)(94 条断言)——`实现方案.md`/README 里承诺的工具必须真的注册;四个 Lean 参数必须同时被文档与代码接受
|
|
812
822
|
|
|
813
823
|
---
|
|
814
824
|
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# dsh-vibe-math 2.3.2 — 四套深度审计:三处高危门禁缺陷 + 撤回语义统一 + 语料确定性
|
|
2
|
+
|
|
3
|
+
> 上一版:2.3.1。本版是**审计驱动**的修复版:对 v2/v3/v4/v5 各做了一轮逐架构深度审计
|
|
4
|
+
> (插件 + 套件 + 实现方案 + persona + 语料),并做了四个架构之间的**横向对照**。
|
|
5
|
+
> 无破坏性变更,默认仍为 `formalVerify: 'off'`。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 0. 三处高危缺陷(都会让"严格验证"失效或不可用)
|
|
10
|
+
|
|
11
|
+
| # | 架构 | 缺陷 | 后果 |
|
|
12
|
+
|---|---|---|---|
|
|
13
|
+
| 1 | **v3** | 四个 Lean 参数**根本没写进 `vibe_math_set_params` 的参数 schema**(该 schema 是 `additionalProperties:false`) | 遵守 schema 的 provider **拒绝这个调用** → 用户**永远无法开启**这个功能;而套件全绿,因为它直接调 handler、**绕过 schema** |
|
|
14
|
+
| 2 | **v2** | `require` 门禁**只读自己那一侧的 id**(`formalOf(rId)`),而代理用**对象 id** 归档、别名同步只更新**已存在**的键 | "归档了 passed、验证侧还没有记录"时门禁**永远搁置**;搁置本身又写下 `rId='none'`,于是**每轮重开一次辩论、对象永远无法定论**、其它对象被饿死 |
|
|
15
|
+
| 3 | **v4** | `formalSetRun` 硬编码 `status:'attempted'`,**把已验证对象的 `passed` 抹掉**(与自己的注释、规格、v2/v5 都矛盾) | 一次随手 `lean_run` 就让对象丢掉"已形式化":投票提示词**丢掉忠实性分支**,`require` 档对**已有绿色归档证明**的对象重新关门 |
|
|
16
|
+
|
|
17
|
+
另有一处**门禁旁路**(v2):`settleVerdict` 的「判断命题」转移在 v=0 时直接写
|
|
18
|
+
`布尔估计=0`/`已验证`/`优先级 never` 并压入 `正确概率:1` 条目,**完全不看门禁**——一个未形式化的
|
|
19
|
+
命题被侧面判为**假**且永久退出调度。已改为先过门禁。
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 1. 撤回语义统一:**删除 → 复核 → 覆盖撤回说明**
|
|
24
|
+
|
|
25
|
+
2.3.1 只在 v5 做对了。本轮把同一语义推广到四套:撤回归档证明时
|
|
26
|
+
|
|
27
|
+
1. 先删(`subprocess` 可用时);
|
|
28
|
+
2. **用 fs 复核文件真的没了**;
|
|
29
|
+
3. 仍在(宿主没有 `subprocess`、shell 静默失败、权限问题)→ **就地覆盖为撤回说明**
|
|
30
|
+
(`-- 已撤回(<时间>):该形式化被认定与命题原文不一致。` + 指向保留的工作文件);
|
|
31
|
+
4. 公告**如实说明**发生了哪一种(删除 / 覆盖 / ⚠ 两者都失败,请不要把它当作该对象的证明)。
|
|
32
|
+
|
|
33
|
+
此外修掉了两处静默漏洞:v2 只从两个 id 收集 `proof`(别名归档的证明留在盘上);v2/v3/v4 用
|
|
34
|
+
`removeFile` 尽力删除且吞掉结果。
|
|
35
|
+
|
|
36
|
+
**同一类问题还有一处**:`lean_archive kind='proof'` 在**这次跑红**时曾保留 `prev.proof`
|
|
37
|
+
(而工作文件已被新代码覆盖)→ `Formal/Index.md` 会同时显示"attempted/fail"与一条**不再成立的**
|
|
38
|
+
`Verified/Lean/…`,忠实性提示词还会打印这个路径。四套统一为"`proof` 只属于 `passed`",并在跑红时
|
|
39
|
+
撤回旧的归档证明(v4 另外把"随手 `lean_run` 不许降级 passed"补回)。
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 2. 提示词/交互修复(逐条都有断言与探针)
|
|
44
|
+
|
|
45
|
+
| 修复 | 说明 |
|
|
46
|
+
|---|---|
|
|
47
|
+
| **按档位承诺**(四套) | 忠实性分支曾**无条件**宣称"本次裁定**不定论**",而只有 `require` 有门禁。现在 require 保留该承诺,encourage 明确写"**本档没有门禁**:请务必给弃权值,以保证本轮无法得出一致结论";defect 公告、TODO/Index 措辞同样按档位分叉 |
|
|
48
|
+
| **无工具链出路点名两个错误码**(四套) | 只写 `LEAN_NOT_FOUND` 时,遇到 `NO_SUBPROCESS`(宿主没有 subprocess 服务)的代理会当成未知失败而重试;现在两个都点出 |
|
|
49
|
+
| **失败提示要可执行**(v3) | `LEAN_NOT_FOUND`/`NO_SUBPROCESS`/`LEAN_SPAWN_FAILED` 没有编译器输出,却提示"按上面的编译器输出修复" → 改为按失败码给不同的出路 |
|
|
50
|
+
| **活动日志里的工具名**(v4) | 代理可读的日志里写着缩写 `lean_run` → 改为注册名 `vibe_v4_lean_run`;注入文本扫描现在也覆盖 `State/session.json` 的 `activityLog` |
|
|
51
|
+
| **路径指向真实位置**(v2) | 工作轮把可复用引理指向项目内的 `Formal/Proved/`——那是**不存在**的路径(全局库在项目树之外)→ 改为 `<VibeMath 根>/Formal/Proved/` |
|
|
52
|
+
| **红灯不许声称可复用**(v2) | `kind='def'/'lemma'` 跑红时工具返回值仍写"已并入全局可复用库,可直接 import 复用" |
|
|
53
|
+
| **`vibe_math_setup` 重复参数**(v3) | `plannerPersona` 出现两行 |
|
|
54
|
+
| **规格里的幽灵工具**(v4,由我的新审计发现) | `实现方案.md` 把 `vibe_v4_propose_verify(targetId)` 写成工具,而 v4 **没有**这个工具(真机制是回执字段 `propose_verify`) |
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## 3. 语料确定性(契约 §10 要求"逐字节可 diff")
|
|
59
|
+
|
|
60
|
+
- **v5**:语料每跑一次都变。根因有三层:心跳/会议唤醒依赖**真实时钟**与异步顺序;捕捉心跳时
|
|
61
|
+
"最闲成员"随时间抖动;写入端**只按 kind 排序**,同 kind 内仍随 drain 顺序变化。
|
|
62
|
+
修法:套件加**虚拟时钟**(`ctx.timeout` 接虚拟队列、`sleep(n)` 推进虚拟时间)+心跳在
|
|
63
|
+
**单成员研究所**内捕捉+写入端**全序排序**(kind → owner → prompt)。
|
|
64
|
+
结果:**连跑 6 次哈希全同**,且套件 **7–9 s → 1.7 s**。
|
|
65
|
+
- **v3**:20 条 `planner:*` 条目带随机 plan id 与 epoch 时间戳 → scrub 归一化 + 断言。
|
|
66
|
+
- **v2/v4**:本已稳定;v4 的语料在套件运行中重生成并验证两次哈希一致。
|
|
67
|
+
- 五份语料(四个预设 + persona)现在都通过我的确定性检查(无绝对路径、无时间戳、可重复)。
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 4. 新增的常驻守卫(随包发布,可一键复核)
|
|
72
|
+
|
|
73
|
+
| 脚本 | 作用 |
|
|
74
|
+
|---|---|
|
|
75
|
+
| `audit-prompt-invariants.mjs` | 把历次**真实发生过的提示词/工具面缺陷类别**编码成四套 × 31 条静态不变式(缩写工具名 / "偏离→0" / `defect` 规则缺失或未实现 / 回执契约缺 `defect` / 无 note 放行 / 字段名错 / `off` 档回执未被门禁 / 语料不确定或缺档位 / 探针缺失 / 按档位承诺 / **封闭的 schema 收不下自己文档里的参数** / **schema 声明了、参数层却静默丢弃的键**)。**当前 145/0**,并带 `--self-probe`:在内存里注入这些缺陷形状,要求对应不变式**变红**、未变异的对照跑**仍为绿**(5/5) |
|
|
76
|
+
| `audit-spec-traceability.mjs` | 规格/README 承诺的工具必须真的注册(**能识别"文档里说它不存在"的否定语境**);四个 Lean 参数必须同时被文档与代码接受;契约 §7 的 `terminate()`;契约 §8 的**门禁收口点无旁路**(调用图检查)。**当前 91/0** |
|
|
77
|
+
| `run-tests.mjs` | 并行跑全部套件,打印每项耗时/加速比/最慢几项(本轮又修了 `--only x` 空格形式被静默忽略、`--json` 混入人类输出两个 bug) |
|
|
78
|
+
| `docs/test-timing.md` | 耗时基线 + 并行安全规则 + 虚拟时钟的适用条件(若套件用 `Date.now()` 做超时判据又用 `setInterval` 轮询,冻结时钟会让判据永不超时,必须连轮询定时器一起虚拟化) |
|
|
79
|
+
|
|
80
|
+
### 4.1 新增「工具参数 schema」守卫:文档写了 ≠ 工具收得下
|
|
81
|
+
|
|
82
|
+
本轮最贵的一处缺陷(v3 开不了档)暴露出一整类**既有测试全都盲**的漏洞:四个预设的工具 schema 都由
|
|
83
|
+
`objParams` 以 `additionalProperties:false` **关闭**,因此 schema 没列出的键会被任何遵守 schema 的
|
|
84
|
+
provider **直接拒绝**——可提示词/规格/状态行可以全都在说这个参数,套件也可以全绿(套件直接调 handler、
|
|
85
|
+
绕过 schema)。现在这层有了三重守卫:
|
|
86
|
+
|
|
87
|
+
1. 四套各自的 `formal-verify-vN.test.mjs` 直接检查**真实注册的** schema 对象:schema 必须仍是封闭的、
|
|
88
|
+
必须声明 `formalVerify`/`leanCommand`/`leanArgs`/`leanTimeoutMs`、`formalVerify` 的 enum 必须恰好是
|
|
89
|
+
三档(**已用探针证明**:把 v3 真实注册那一份里的 `leanArgs` 去掉,套件立刻变红);
|
|
90
|
+
2. `audit-prompt-invariants.mjs` 的 I13:**每一处** set 工具定义(v2/v3 有"会话 handler 表"与
|
|
91
|
+
"真实注册"两份)都必须声明这四个参数,且每一份 `objParams` 都必须关闭 schema;
|
|
92
|
+
3. 同脚本的 I14:schema **声明的每个键**都必须被参数层真正接收(v2/v3 的闸门是 `DEFAULT_PARAMS` 键集、
|
|
93
|
+
v4 是 `k in params`、v5 是 `normalizeParams` 的类型列表)——声明而不接收 = 调用返回 `{ok:true}`
|
|
94
|
+
而什么都不发生,是最容易被读成"设置成功"的静默失效。
|
|
95
|
+
|
|
96
|
+
`AUDIT-CHECKLIST.md` 新增 **§1.8「四套同构:任何语义修正必须四套同步」**——本轮三处高危里有两处正是
|
|
97
|
+
"改了一套、另三套没改"或"四套共用同一写法而没人横向对照"造成的。
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## 5. 测试与探针(实测)
|
|
102
|
+
|
|
103
|
+
| 套件 | 2.3.1 | 2.3.2 |
|
|
104
|
+
|---|---|---|
|
|
105
|
+
| `formal-verify-v2.test.mjs` | 261 | **319** |
|
|
106
|
+
| `formal-verify-v3.test.mjs` | 247 | **283** |
|
|
107
|
+
| `formal-verify-v4.test.mjs` | 226 | **269** |
|
|
108
|
+
| `formal-verify-v5.test.mjs` | 120 | **145** |
|
|
109
|
+
| `prompt-v5-integrity.test.mjs` | 588 | **506**(语料去重:心跳只记 1 条)+ 虚拟时钟 |
|
|
110
|
+
| `e2e-v4-fixes.test.mjs` | 120 | 120(**修掉并行下的抖动**:T21 的会议看门狗 80 ms 在 CPU 争用下提前放弃会议) |
|
|
111
|
+
|
|
112
|
+
- 全量回归:**连续 3 次并行跑,23/23 全绿**(wall ≈111 s,最新一次实测 wall 111.5 s / sum 221.5 s / x1.99,
|
|
113
|
+
关键路径 `e2e-v4-fixes` 98.1 s);
|
|
114
|
+
- `audit-formal-sensitivity.mjs`:**49 条探针全部按预期变红,0 问题**;
|
|
115
|
+
- `audit-prompt-invariants.mjs`:**145/0**,`--self-probe` **5/5**;`audit-spec-traceability.mjs` **91/0**;
|
|
116
|
+
- `audit-persona-sensitivity.mjs`:11/11 变红;`audit-persona-surface.test.mjs` 197/0;
|
|
117
|
+
- `audit-v5-integrity.mjs` clean;四套 `audit-registration.mjs` 无重复/无缺失;
|
|
118
|
+
- 新增两条 **schema 级探针**:把 v3 真实注册的 schema 里 `leanArgs` 去掉 → v3 套件变红(已实测);
|
|
119
|
+
在 v4/v5 里造一个"声明但不接收"的参数 → `audit-prompt-invariants.mjs` 变红(已实测)。
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## 6. 仍然存疑、需要人决定的政策问题(不是 bug,故未擅自改)
|
|
124
|
+
|
|
125
|
+
1. **跑红的 `kind='proof'` 是否应撤销旧证明**:本轮按"`proof` 只属于 `passed`"(契约 §4)统一四套;
|
|
126
|
+
若你认为"随手一次失败不该抹掉已证结论",应改**契约**而不是改代码。
|
|
127
|
+
2. **`off` 档"主动调用工具"算不算无操作**:契约 §2 明确工具仍可用,但那会写 `Formal/Index.md`/状态/公告;
|
|
128
|
+
四个审计都把它记为 policy call,现已在规格里澄清"off 约束的是**框架自身**,主动调用是显式行为"。
|
|
129
|
+
3. **`used` 回执的语义**:契约状态表字面写"→ attempted",而四套实现都**保留** `passed`/`blocked`
|
|
130
|
+
(否则每条"我用了它"的回执都会把 passed 打回 attempted 并重新关门)。建议改契约字面。
|
|
131
|
+
4. **v2 的 id 解析歧义(真实可达)**:`formalObjectIdOf` 把"对象 id 本身以 `-sN/-pfN/-rfN` 结尾"的
|
|
132
|
+
rId 解析错(`r-p-s1 → p`):这类命题的提示词/卡片会引用**另一个对象**的证明、门禁会被那个对象的
|
|
133
|
+
`passed` 放行。正确修法是**在记录里落权威 `objectId`**,但这要先把契约定下来。
|
|
134
|
+
5. **只剩"被门禁搁置"的对象时**:调度器会空转(不会卡死、不会误判终止)——契约没写这种局面该终止还是空转。
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## 7. 升级
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
npm i dsh-vibe-math@latest
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
无迁移:新参数默认 `off`,四套既有行为与 `off` 一致。升级后重启 DSH;未被手动改过的 preset 文件
|
|
145
|
+
会自动更新。
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# dsh-vibe-math 2.3.3 — 确认轮审计:`used` 回执曾撤销已成立的证明(v2)+ 契约字面纠错 + 守卫自身加固
|
|
2
|
+
|
|
3
|
+
> 上一版:2.3.2。本版是 2.3.2 之后的**确认轮**(round 3)结果:重新审计本轮改动过的每一处
|
|
4
|
+
> (四套插件、四套套件、共享契约、审计脚本自身),又抓到一处**真实缺陷**、一处**契约与实现字面
|
|
5
|
+
> 相反**、以及一处**守卫自身的脆弱点**。无破坏性变更,默认仍为 `formalVerify: 'off'`。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. 真实缺陷:一次 `used` 回执会**撤销已成立的证明**(只有 v2)
|
|
10
|
+
|
|
11
|
+
`formal.decision='used'` 的语义是"这一轮碰了形式化 / 写了一份草稿"。契约 §4 里**只有 `defect`
|
|
12
|
+
能撤销证明**,因为撤销意味着审查对象从"忠实性"退回"推导是否正确"、`require` 档对一份**已经跑通的
|
|
13
|
+
归档证明重新关门**。
|
|
14
|
+
|
|
15
|
+
| 架构 | `used` 回执对已有 `passed`/`blocked` 的处理(修复前) |
|
|
16
|
+
|---|---|
|
|
17
|
+
| v3 / v4 / v5 | 保留 `passed`(v3 只保留 passed,`blocked` 会被打回 attempted——见 §2) |
|
|
18
|
+
| **v2** | **无条件写 `status:'attempted'`** —— 而降级发生在**两个 id 空间**上,`proof` 指针还留着,记录自相矛盾 |
|
|
19
|
+
|
|
20
|
+
后果链(实测):对象已 `passed` → 表决者回一句"我这轮又写了遍草稿" → 记录降级为 `attempted`、
|
|
21
|
+
`status.formal.objects` 里不再是 `passed` → 后续审查提示词**丢掉忠实性分支** → `require` 档对一份
|
|
22
|
+
跑通的证明**重新关门**、对象被丢进「形式化待办」。
|
|
23
|
+
|
|
24
|
+
> 这正是 2.3.2 修过的 v4 `formalSetRun` 缺陷的**同一类**("随手一次动作把 passed 抹掉"),
|
|
25
|
+
> 只是长在另一条路径(回执通道)上,而且**只长在一套里**——`AUDIT-CHECKLIST §1.8`(四套同构)
|
|
26
|
+
> 记的就是这种形态。
|
|
27
|
+
|
|
28
|
+
**修复**:v2 的 `used` 分支改为先看**两套 id 空间**的状态(对象侧自己的记录 + `formalGateRecord` 的合并
|
|
29
|
+
视图),取其中**最强**的一个(`passed` > `blocked` > `attempted`):只有两侧都还没尝试过才写 `attempted`,
|
|
30
|
+
否则保留原状态并在活动日志里说明保留了哪一个。四套现在**同构**(v3 另外补上 `blocked` 的保留,见 §2)。
|
|
31
|
+
|
|
32
|
+
## 2. 同一类的第二处:v3 的 `used` 只保留 `passed`,会把 `blocked` 打回 attempted
|
|
33
|
+
|
|
34
|
+
`blocked` 是**门禁已放行**的记录(契约 §4/§8)。v3 的条件写成 `prev.status === 'passed' ? 'passed' : 'attempted'`:
|
|
35
|
+
一个已经用"显式阻塞原因"打开门禁的对象,被一句 `used` 回执打回 `attempted`,门禁**重新关上**。
|
|
36
|
+
已改为 `passed`/`blocked` 都保留(与 v2/v4/v5 一致)。
|
|
37
|
+
|
|
38
|
+
## 3. 契约字面与实现相反(三处)
|
|
39
|
+
|
|
40
|
+
`docs/formal-verification.md` §4 的迁移表是四套的规范来源,但它有两行写错了(代码是对的):
|
|
41
|
+
|
|
42
|
+
| 行 | 原字面 | 现字面 |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| `formal:{decision:'used'}` | → `attempted` | → `attempted`;**若已是 `passed`/`blocked` 则保持原状**(撤销只有 `defect` 一条路) |
|
|
45
|
+
| `lean_run` 成功/失败 | → `attempted` | 同样**不降级**已成立的 `passed`/`blocked` |
|
|
46
|
+
| (新增)`lean_archive{kind:'proof'}` + **运行失败** | 未写 | → `attempted`、清空 `proof`、并**撤回**旧的归档证明(工作文件刚被覆盖,旧证明不再对应任何代码) |
|
|
47
|
+
|
|
48
|
+
四套的 `实现方案.md` 与 v5 规格里的对应句子同步改正。规范文档写反最危险的地方在于:**下一次修改是
|
|
49
|
+
照它写的**(2.3.2 修好 `used` 之后,如果只读契约就会把修复改回去)。
|
|
50
|
+
|
|
51
|
+
## 4. 守卫自身的脆弱点:注释扫描器不认正则字面量
|
|
52
|
+
|
|
53
|
+
`audit-prompt-invariants.mjs` 的 I1/I13/I14 都建立在"先把注释抹掉、再检查剩下的代码"之上。四个预设里
|
|
54
|
+
都有 `/[\\/:*?"<>|\u0000-\u001f]+/` —— **字符类里含一个双引号**。原扫描器把那个引号当成字符串开头,
|
|
55
|
+
此后整个文件的词法状态就是错的。实测差异:
|
|
56
|
+
|
|
57
|
+
| 预设 | 两种扫描器**逐行不同**的行数 | 典型后果 |
|
|
58
|
+
|---|---|---|
|
|
59
|
+
| v2 | 190 行 | 真实代码行(如 `const abs = …`)被当成注释**抹掉** → 真缺陷可能被漏看 |
|
|
60
|
+
| v3 | 159 行 | 同上 |
|
|
61
|
+
| v4 | 14 行 | 注释被当成代码 → 反模式写进注释就会**误报** |
|
|
62
|
+
| v5 | 121 行 | 同上 |
|
|
63
|
+
|
|
64
|
+
本轮给扫描器加了**正则字面量**支持(含字符类 `[...]`、转义、结尾 flags),并把"守卫的守卫"写成
|
|
65
|
+
**X5–X7 三条自检**(放进 `audit-prompt-invariants.mjs`,任何一次运行都会执行):正则里的引号不得吞掉
|
|
66
|
+
后面的注释、字符串里的 `//`(URL)不得被当成注释、转义斜杠不得提前结束正则,且三者都必须保持行结构。
|
|
67
|
+
实测修复前 X5 变红、修复后全绿。
|
|
68
|
+
|
|
69
|
+
## 5. 本轮新增的行为断言(四套同构,+42 条;另 +6 不变式 / +3 可追溯)
|
|
70
|
+
|
|
71
|
+
| 断言(四套各一份) | 说明 |
|
|
72
|
+
|---|---|
|
|
73
|
+
| `used` 回执**不得**降级已 `passed` 对象 | 记录与 `proof` 指针都保留;v2 修复前**实测变红**(`got attempted`),修复后全绿 |
|
|
74
|
+
| `used` 回执**不得**把 `blocked` 打回 `attempted`(门禁不得被重新关上) | v3 修复前变红 |
|
|
75
|
+
| 一次普通 `lean_run`(带 `target`)**不得**降级 `passed` | 此前只有 v4 套件有这条断言,现四套齐备 |
|
|
76
|
+
| `used` 之后 `require` 门禁**仍然放行** | v2:把该轮驱动到一致为真,断言**没有**产生 `formal-required` 待办 |
|
|
77
|
+
| 真实注册的 schema 必须仍是封闭的、且四个 Lean 参数齐全(2.3.2 的守卫) | 四套各 7 条 |
|
|
78
|
+
|
|
79
|
+
## 5.1 并行回归暴露的**测试脆弱性**(也一并修掉)
|
|
80
|
+
|
|
81
|
+
4 路并行回归第二次跑时 `e2e-v4-fixes` **崩了**(exit 1,只跑了 2 个用例就中止);单独跑 3 次全绿
|
|
82
|
+
(120/120)。形态:驱动循环"安静即停"在框架把卡片落盘**之前**退出 → `assert(existsSync(card))`
|
|
83
|
+
只记录失败**不抛** → 紧随其后的 `readFileSync(card)` 抛 `ENOENT` → **未捕获异常让整个套件中止,
|
|
84
|
+
后面 12 个用例的断言全部丢失**。
|
|
85
|
+
|
|
86
|
+
修法(两条一起):该套件新增 `readArtifact(p, ms=3000)`(先等产物、再防御性读),并把六处"断言后立刻
|
|
87
|
+
读产物"改成"先等产物 → 再断言 → 防御性读"。效果:慢机器上产物晚到 3 秒也能通过;真没写出来则是
|
|
88
|
+
**一条干净的断言失败**,不再吞掉后续用例。这条已写进 `AUDIT-CHECKLIST` §4(连同"发布元数据交给
|
|
89
|
+
序列化器、不要用字符串替换手写 `package.json`"——本轮就这么写出过一次非法 JSON)。
|
|
90
|
+
|
|
91
|
+
## 6. 验收(实测)
|
|
92
|
+
|
|
93
|
+
| 套件 / 脚本 | 2.3.2 | 2.3.3 |
|
|
94
|
+
|---|---|---|
|
|
95
|
+
| `formal-verify-v2.test.mjs` | 319 | **334** |
|
|
96
|
+
| `formal-verify-v3.test.mjs` | 283 | **294** |
|
|
97
|
+
| `formal-verify-v4.test.mjs` | 269 | **277** |
|
|
98
|
+
| `formal-verify-v5.test.mjs` | 145 | **153** |
|
|
99
|
+
| `audit-prompt-invariants.mjs` | 145 | **151**(+ X5–X7 扫描器自检及其行结构断言) |
|
|
100
|
+
| `audit-spec-traceability.mjs` | 91 | **94**(契约 §4 三行的字面校验) |
|
|
101
|
+
| `audit-prompt-invariants.mjs --self-probe` | 5/5 | **5/5** |
|
|
102
|
+
| `prompt-v5-integrity.test.mjs` | 506 | 506(语料字节稳定) |
|
|
103
|
+
| `audit-persona-surface.test.mjs` | 197 | 197 |
|
|
104
|
+
|
|
105
|
+
- 全量并行回归 23/23 全绿;49 条 formal 探针全红;四套语料(v2/v3/v4/v5 + persona)连续两次哈希一致;
|
|
106
|
+
- closing verification:**18/18 阶段通过**。
|
|
107
|
+
|
|
108
|
+
## 7. 升级
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
npm i dsh-vibe-math@latest
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
无迁移。新参数默认 `off`,四套在 `off` 档的行为与 2.3.2 完全一致;本版改动只影响
|
|
115
|
+
`formalVerify` 非 `off` 时的记账语义(且都是"少撤销、不误关门"方向)。
|
|
@@ -231,14 +231,23 @@ const CONCURRENCY = (() => {
|
|
|
231
231
|
return Math.max(1, Number.isFinite(v) ? v : 1)
|
|
232
232
|
})()
|
|
233
233
|
const ONLY = (() => {
|
|
234
|
-
const
|
|
235
|
-
|
|
234
|
+
const eq = process.argv.find((a) => a.startsWith('--only='))
|
|
235
|
+
if (eq) return eq.split('=')[1]
|
|
236
|
+
// also accept the space form (`--only v5`), which the usage line advertises
|
|
237
|
+
const i = process.argv.indexOf('--only')
|
|
238
|
+
return i >= 0 && process.argv[i + 1] && !process.argv[i + 1].startsWith('--') ? process.argv[i + 1] : ''
|
|
236
239
|
})()
|
|
237
240
|
const selected = probes.filter((p) => !ONLY || p.name.includes(ONLY) || p.preset === ONLY)
|
|
238
241
|
if (process.argv.includes('--list')) {
|
|
239
242
|
for (const p of selected) console.log(p.preset + ' ' + p.name)
|
|
240
243
|
process.exit(0)
|
|
241
244
|
}
|
|
245
|
+
// A filter that matches nothing must FAIL, not report success: with zero probes the summary below
|
|
246
|
+
// would say "0 problems / ALL PROBES RED" — a textbook false green (AUDIT-CHECKLIST §2.5).
|
|
247
|
+
if (selected.length === 0) {
|
|
248
|
+
console.error('no probes matched' + (ONLY ? ' --only=' + ONLY : '') + ' — refusing to report success on an empty run')
|
|
249
|
+
process.exit(2)
|
|
250
|
+
}
|
|
242
251
|
|
|
243
252
|
function runAsync(cmd, args, opts) {
|
|
244
253
|
return new Promise((resolve) => {
|