dsh-vibe-math 2.7.1 → 2.7.2

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.
Files changed (47) hide show
  1. package/README.en.md +681 -690
  2. package/README.md +8 -17
  3. package/cordis.patch.yml +6 -6
  4. package/docs/AUDIT-CHECKLIST.md +518 -518
  5. package/docs/COMPAT-AUDIT-ROUND3.md +154 -154
  6. package/docs/final-paper.md +172 -172
  7. package/docs/formal-verification.md +588 -588
  8. package/docs/math-computation.md +187 -163
  9. package/docs/release-notes/README.en.md +48 -0
  10. package/docs/release-notes/README.md +47 -0
  11. package/docs/release-notes/RELEASE-NOTES-2.7.2.en.md +72 -0
  12. package/docs/release-notes/RELEASE-NOTES-2.7.2.md +72 -0
  13. package/docs/release-notes/TEMPLATE.md +120 -0
  14. package/docs/test-timing.md +154 -154
  15. package/package.json +208 -203
  16. package/prompt-corpus-persona/persona-corpus.json +8 -8
  17. package/prompt-corpus-persona/persona-corpus.md +12 -12
  18. package/prompt-corpus-v2/formal-verify-v2.json +121 -109
  19. package/prompt-corpus-v2/formal-verify-v2.md +223 -107
  20. package/prompt-corpus-v3/formal-verify-v3.json +100 -76
  21. package/prompt-corpus-v3/formal-verify-v3.md +268 -70
  22. package/prompt-corpus-v4/formal-verify-v4.json +10 -10
  23. package/prompt-corpus-v4/formal-verify-v4.md +20 -20
  24. package/prompt-corpus-v5/prompt-corpus-v5.json +81 -81
  25. package/prompt-corpus-v5/prompt-corpus-v5.md +138 -128
  26. package/tests/audit-math-computation-contract.mjs +43 -1
  27. package/tests/audit-math-computation-sensitivity.mjs +2 -2
  28. package/tests/audit-v5-sensitivity.mjs +3 -1
  29. package/tests/e2e-v5-round2.test.mjs +114 -5
  30. package/tests/formal-verify-v2.test.mjs +38 -0
  31. package/tests/formal-verify-v3.test.mjs +33 -0
  32. package/tests/formal-verify-v4.test.mjs +87 -0
  33. package/tests/math-computation-shared.test.mjs +126 -1
  34. package/vibe-math-v2/agent.cordis.yml +2 -2
  35. package/vibe-math-v2/math-computation.js +122 -11
  36. package/vibe-math-v2/vibe-math-v2.js +75 -11
  37. package/vibe-math-v3/agent.cordis.yml +2 -2
  38. package/vibe-math-v3/math-computation.js +122 -11
  39. package/vibe-math-v3/vibe-math-v3.js +60 -13
  40. package/vibe-math-v4/agent.cordis.yml +4 -4
  41. package/vibe-math-v4/math-computation.js +122 -11
  42. package/vibe-math-v4/vibe-math-v4.js +55 -15
  43. package/vibe-math-v5/agent.cordis.yml +4 -4
  44. package/vibe-math-v5/math-computation.js +122 -11
  45. package/vibe-math-v5/vibe-math-v5.js +137 -28
  46. package/vibe-math-v5//345/256/236/347/216/260/346/226/271/346/241/210.md +1660 -1655
  47. package/vibe-math-v5//346/236/266/346/236/204/345/233/276.md +693 -693
@@ -0,0 +1,72 @@
1
+ # dsh-vibe-math 2.7.2 — Release Notes (English)
2
+
3
+ > Previous release: 2.7.1. This is a **PATCH release that contains fixes and additive response fields only** — no existing behaviour contract changes. It completes **engine discovery, evidence and diagnostics** on real hosts: an engine that is installed but not on `PATH` is now found, install guidance never hands over a command that cannot run, and failure evidence (timeout, missing packages, unenforced constraints) is neither absent nor silent. The archive identity and the participant-set semantics are directly checkable. Parameter defaults, data formats and the directory layout are **unchanged**, the DSH support window is unchanged, and **no migration is needed**.
4
+
5
+ ## Overview
6
+
7
+ - **More reliable discovery on real hosts**: discovery now runs PATH → runtimes shipped by the host → **the known per-OS install locations**, so an engine installed in its default directory but never added to `PATH` (R, for example) is found.
8
+ - **No more unrunnable install commands**: `MATH_ENGINE_NOT_FOUND` only offers an executable command when that package manager really exists on this machine; otherwise it gives the suggested command, the official location and the reason.
9
+ - **`probe` no longer reports only the good news**: besides the engines that resolved, it names the **configured but not found** engines and why.
10
+ - **Complete failure evidence**: `MATH_TIMEOUT` carries the same fields as `MATH_NONZERO_EXIT`, and a timeout's partial output is available in **both the response and the receipt**.
11
+ - **The constraint policy is stated**: version constraints are **checked for existence only and never enforced**, and the constraints that were not checked are listed instead of being dropped silently.
12
+ - **Checkable archive identity**: the run response carries the archive id and attempt, and the "edit an archived script, then re-run" semantics are explained by an explicit field and warning.
13
+ - **One participant set per verify/meeting (v4/v5)**: the roster is snapshotted with a version, every view reads the same snapshot, and the version increments when the set really changes so a stale set is detectable.
14
+ - **More specific diagnostics**: member-level failures return a code, the current state and a next step instead of a bare "no such resident".
15
+
16
+ ## Added
17
+
18
+ - The `math_computation` `run` response now carries **`runId`** and **`attempt`** (previously the archive id existed only inside the receipt, so a caller could not verify "same archive").
19
+ - The `probe` response now carries **`configured`** (every engine enabled in the configuration) and **`absent[]`**, where each missing engine states **`why`** (`not-found-on-this-machine` or `needs-a-caller-supplied-command`).
20
+ - Constraint policy fields: both a successful response and a "missing packages" failure carry **`versionPolicy`** and **`constraintsNotEnforced`** (the constraints that were **not** checked, or an empty array).
21
+ - `MATH_TIMEOUT` responses carry **`stdout`**/**`stderr`** (capped); the receipt JSON carries **`partialStdout`**/**`partialStderr`**.
22
+ - `MATH_ENGINE_NOT_FOUND`'s `next` carries **`suggestedCommand`**, **`packageManager`**, **`packageManagerAvailable`** and **`note`** (plus `vendorUrl` where the engine has one).
23
+ - The `run` response carries **`fileIsArchivedScript`**, and emits an **`ARCHIVED_SCRIPT_RERUN`** warning when `mode:'file'` targets an archived script.
24
+ - v4: `status()` carries **`rosterVersion`** and **`frozenParticipants`**; the `consensus` / `meeting` / `verify` views carry their own `rosterVersion`.
25
+ - v4: the `paper` view carries **`dirProjected`** / **`dirSource`** / **`readSideEffect`**, saying whether the path is a projection or real state.
26
+ - v2/v3: decision and sub-agent interrupt diagnostics carry **`code`** and **`next`** (for example `VIBE_MATH_DECISION_NOT_FOUND`, with the current queue state); v4 member-level calls carry **`V4_NO_SUCH_RESIDENT`** with the current roster and a next step.
27
+
28
+ ## Changed
29
+
30
+ - **Discovery order**: PATH → runtimes shipped by the host → the known per-OS install locations (Windows `%ProgramFiles%`, `%ProgramFiles(x86)%`, `%LOCALAPPDATA%\Programs`; the macOS framework path; Linux `/usr/lib/R`, `/opt/R`, and similar). **Existence is always proven by listing a directory**, never assumed.
31
+ - **Install guidance**: `next.command` is an executable command only when the corresponding package manager resolves on this machine; otherwise it is empty and a `note` plus the official location is given. Installation is still plan → `planToken` confirmation → execution, with user scope by default.
32
+ - **The archive key**: `mode:'file'` is keyed by the **source path** and `mode:'code'`/`'expr'` by the script content. Editing the **same source file** and re-running therefore lands on the **same archive** (`attempt ≥ 2`, `scriptChanged:true`, `previousReceipt` pointing at the previous attempt, and the earlier attempt is never overwritten). Pointing at a **different path** (a copy of the archived script, say) writes a **new archive**, where `attempt:1`, `scriptChanged:false` and `previousReceipt:null` are **expected**. The archive id contains no random value.
33
+ - **v4 roster freeze and prune**: a verify/meeting freezes its participant set and records `rosterVersion`; **removing a member also prunes it from the frozen set** (otherwise in-flight votes could never close), **new members do not join a frozen set**, and `rosterVersion` increments whenever the set really changes. With no verify/meeting in progress, `status().frozenParticipants` is an explicit `null`.
34
+ - **v2/v3 single-source vote counting**: the per-round counts come from one function (`voteCount`, reading the **expectation recorded when the verify task was created** plus the round), so the four readers (enough votes, all reported, consensus, final verdict) no longer derive them separately — raising or lowering the verifier count can no longer make the views disagree. **Deliberately unchanged**: the `MIN_REVIEWERS` floor and the "everyone agrees" predicate. That combination — not a simplified predicate over the current round alone — is what decides when a verification may conclude; collapsing the two would let a single reviewer's verdict be accepted too early.
35
+ - **Documentation** now states the verification boundary, the known differences and the new response fields, including the engine versions verified on real hosts and the confirmed edge codes.
36
+
37
+ ## Fixed
38
+
39
+ - **Installed but invisible engines**: scanning only the host process's PATH reported an engine installed in its default directory (measured: R 4.6.1) as missing; it is now discovered from the known install locations and version-probed like any other candidate.
40
+ - **Unrunnable install commands**: the tool used to suggest a package manager that does not exist on the machine (for example `winget`); it now only offers the command when the manager resolves, and otherwise gives the official location plus an explanation.
41
+ - **Incomplete timeout evidence**: `MATH_TIMEOUT` previously lacked `exit` and `stderr`, and its partial output existed only in the on-disk `stdout.txt`; the response and the receipt now both carry the capped partial output, aligned with `MATH_NONZERO_EXIT`.
42
+ - **`probe` listing only what worked**: the availability line could show a few engines without explaining the rest of the configuration; it now names the **configured but not found** engines and why.
43
+ - **Version constraints silently ignored**: the response now states that constraints are existence-only and lists every constraint it did **not** check.
44
+ - **Confusing "edit an archived script, then re-run"**: an explicit field and warning now distinguish "targeting a copy of an archive ⇒ a new archive with no history" from "targeting the original source ⇒ the same archive with a new attempt", and state that an old receipt is not evidence for edited code.
45
+ - **A misleading `paper` field in v4**: with no paper state the field is a **projected path**; it is now flagged via `dirProjected`/`dirSource` and declares that reading `status` has no filesystem side effect.
46
+ - **Path basis in member-visible material**: all four presets now state that member file tools resolve against the **session cwd**, that the listed relative paths need the **absolute project-root prefix**, and that computation artifacts should be opened via the absolute `receipt.scriptAbs` or by joining `receipt.cwd` with `receipt.scriptPath`.
47
+ - **Member-level calls answering only "not found"**: v4 now returns an error code, the current roster and a next step; v2/v3 decision and interrupt diagnostics likewise return `code` and `next`.
48
+
49
+ ## Compatibility & Migration
50
+
51
+ - **Breaking changes: none.** Parameter defaults, data formats and the directory layout of all four presets are unchanged.
52
+ - **Additive only**: every field added in this release is additional; please ignore unknown fields rather than failing on them.
53
+ - **Migration: none needed.**
54
+ - The DSH support window is the same as 2.7.1 (see `engines.dsh` in `package.json`).
55
+
56
+ ## Known Limitations
57
+
58
+ - **Octave / Julia are not shipped** and were not installed on the verification machine; their templates and install plans are statically validated but have not been executed on a real host.
59
+ - **Commercial engine templates (MATLAB / Maple / Wolfram)** still need confirmation on a licensed machine and remain marked `VERIFY` by default.
60
+ - **Version constraints are existence-only**: version solving still belongs to the package manager; this tool does not parse constraints.
61
+ - **The plugin cannot enforce network or write restrictions**: the subprocess channel has no policy slot; that requires a host-side sandbox.
62
+ - **Release notes before 2.7.0 are Chinese-only** (see the English history index in `README.en.md`).
63
+
64
+ ## Verification
65
+
66
+ - `node tests/run-tests.mjs` — all green (65 items: 44 suites + 21 sensitivity probes).
67
+ - Three math-contract guards: `tests/audit-math-computation-parity.mjs`, `-contract.mjs`, `-sensitivity.mjs`.
68
+ - Real-host verification (python 3.12.10 and R 4.6.1): both engines produce the same numbers for the same computation; the native path and the `cli` escape hatch agree numerically and share the same `scriptHash`; timeout → `MATH_TIMEOUT`, syntax error → `MATH_NONZERO_EXIT` (with stderr and a receipt), missing package → `MATH_MISSING_PACKAGES` (no receipt directory written), an engine warning → a normal exit with stderr preserved.
69
+
70
+ ## Dependencies
71
+
72
+ - **No new runtime dependencies**; the DSH support window is unchanged.
@@ -0,0 +1,72 @@
1
+ # dsh-vibe-math 2.7.2 — 发布说明
2
+
3
+ > 上一版本:2.7.1。本版是**补丁版:只包含修复与附加(新增)响应字段**,不改变任何既有行为契约——把真实引擎环境下的**发现、证据与诊断**补齐:装了但不在 PATH 的引擎能被发现、安装建议不再给出本机跑不了的命令、失败证据(超时/缺包/未校验约束)不再缺失或静默、归档身份与名册口径可直接核对。四套预设的**参数默认值、数据格式与目录结构未变**,DSH 支撑窗口不变,**无需迁移**。
4
+
5
+ ## 概述
6
+
7
+ - **真实引擎发现更可靠**:引擎发现顺序为 PATH → 宿主自带运行时 → **各操作系统的已知安装目录**,因此在默认目录安装、但没有加进 PATH 的引擎(例如 R)也能被发现。
8
+ - **不再给出跑不了的安装命令**:`MATH_ENGINE_NOT_FOUND` 只在本机的包管理器**确实存在**时才给出可执行命令,否则给出建议命令与官方地址,并说明原因。
9
+ - **`probe` 不再"报喜不报忧"**:除了可用引擎,还会列出**已配置但本机未发现**的引擎及原因。
10
+ - **失败证据完整**:`MATH_TIMEOUT` 与 `MATH_NONZERO_EXIT` 携带同样的证据字段,超时的部分输出在**响应与回执**里都能拿到。
11
+ - **约束口径明说**:版本约束**只按存在性检查、从不校验**,未校验的约束会被逐条列出,不再静默忽略。
12
+ - **归档身份可核对**:运行响应直接给出归档 id 与 attempt;"编辑归档脚本后重跑"的语义有显式字段与警告解释。
13
+ - **名册口径统一(v4/v5)**:一次验证/会议冻结一份名册快照并记录版本号,所有视图读同一份数据;成员变化时版本号递增,读到的集合是否过期一目了然。
14
+ - **诊断更具体**:成员级调用失败时给出错误码、当前状态与下一步建议(而不是一句"不存在")。
15
+
16
+ ## 新增
17
+
18
+ - `math_computation` 的 `run` 响应新增 **`runId`** 与 **`attempt`**(此前归档 id 只存在于回执里,调用方无法直接核对"是不是同一个归档")。
19
+ - `probe` 响应新增 **`configured`**(配置启用的引擎全集)与 **`absent[]`**:每个未发现的引擎带 **`why`**(`not-found-on-this-machine` 或 `needs-a-caller-supplied-command`)。
20
+ - 新增约束口径字段:成功响应与"缺包"失败都带 **`versionPolicy`** 与 **`constraintsNotEnforced`**(本次**未校验**的约束逐条列出;没有约束时为空数组)。
21
+ - `MATH_TIMEOUT` 响应新增 **`stdout`**/**`stderr`**(按上限截断);回执 JSON 新增 **`partialStdout`**/**`partialStderr`**。
22
+ - `MATH_ENGINE_NOT_FOUND` 的 `next` 新增 **`suggestedCommand`**、**`packageManager`**、**`packageManagerAvailable`**、**`note`**(`vendorUrl` 视引擎而定)。
23
+ - `run` 响应新增 **`fileIsArchivedScript`**,并在 `mode:'file'` 指向归档脚本时给出 **`ARCHIVED_SCRIPT_RERUN`** 警告。
24
+ - v4:`status()` 新增 **`rosterVersion`** 与 **`frozenParticipants`**;`consensus` / `meeting` / `verify` 视图带各自的 `rosterVersion`。
25
+ - v4:`paper` 视图新增 **`dirProjected`** / **`dirSource`** / **`readSideEffect`**,明确该路径是投影还是真实状态。
26
+ - v2/v3:决策与子代理中断诊断新增 **`code`** 与 **`next`**(例如 `VIBE_MATH_DECISION_NOT_FOUND`,并说明队列现状);v4 的成员级调用新增 **`V4_NO_SUCH_RESIDENT`**(带当前编制与下一步建议)。
27
+
28
+ ## 变更
29
+
30
+ - **引擎发现顺序**:PATH → 宿主自带运行时 → 已知的每操作系统安装目录(Windows 的 `%ProgramFiles%` / `%ProgramFiles(x86)%` / `%LOCALAPPDATA%\Programs`,macOS 的 framework 路径,Linux 的 `/usr/lib/R`、`/opt/R` 等)。**存在性一律靠列目录证明**,从不假设路径存在。
31
+ - **安装建议**:只有在本机能解析出对应包管理器时,`next.command` 才是可执行命令;否则为空,并给出 `note` 与官方地址。安装流程仍是"计划 → `planToken` 确认 → 执行",作用域默认用户级。
32
+ - **归档 id 的键**:`mode:'file'` 以**源路径**为键,`mode:'code'`/`'expr'` 以脚本内容为键。因此编辑**同一个源文件**再跑会落到**同一个归档**(`attempt ≥ 2`、`scriptChanged:true`、`previousReceipt` 指向上一次,且旧 attempt 绝不被覆盖);而指向**另一个路径**(例如上一份归档的副本)会写入**新归档**,此时 `attempt:1`、`scriptChanged:false`、`previousReceipt:null` 都是**预期**。归档 id 不含随机数。
33
+ - **v4 名册冻结与修剪**:验证/会议开始时冻结参与集合并记录 `rosterVersion`;**移除成员会同时从冻结集合中剔除**(否则在飞投票永远凑不齐),**新增成员不进入已冻结集合**,集合真正变化时 `rosterVersion` 递增。没有进行中的验证/会议时,`status().frozenParticipants` 为显式 `null`。
34
+ - **v2/v3 票数与法定人数单一来源**:每轮票数只由一个函数(`voteCount`,读**验证任务创建时**记录的期望人数快照 + 轮次)给出,"是否够票、是否都报、共识、最终判定"四个读取点不再各自重算,因此调高/调低验证人数不会让各视图分叉。**刻意保持不变**:`MIN_REVIEWERS` 下限与"全体一致"判据——正是这两条(而不是把判据简化成只看本轮)决定了什么时候能收束;把它们一起"简化"掉会让单审阅者的结论被过早采纳。
35
+ - **文档口径更新**:计算工具的验证边界、已知差异与响应字段都写进了随包文档(含真机验证过的引擎版本与边界码)。
36
+
37
+ ## 修复
38
+
39
+ - **装了却"看不见"的引擎**:只扫描宿主进程 PATH 时,安装在默认目录但未加入 PATH 的引擎(实测:R 4.6.1)会被报成缺失;现在能从已知安装目录发现,并且版本探测与其他候选一致。
40
+ - **跑不了的安装命令**:此前会给出本机并不存在的包管理器命令(例如 `winget`);现在只在管理器确实存在时给出命令,否则给出官方地址与说明。
41
+ - **超时证据不完整**:`MATH_TIMEOUT` 之前缺少 `exit` 与 `stderr`,部分输出只存在于磁盘上的 `stdout.txt`;现在响应与回执都带截断后的部分输出,字段与 `MATH_NONZERO_EXIT` 对齐。
42
+ - **`probe` 只报可用项**:可用性一行此前可能只列出少数引擎而不解释其余配置项;现在点名"已配置但本机未发现"的引擎与原因。
43
+ - **版本约束被静默忽略**:现在明确说明"只按 base name 检查是否存在",并把本次未校验的约束逐条列出。
44
+ - **归档脚本"编辑后重跑"易被误读**:新增显式字段与警告说明"指向归档副本 ⇒ 新归档、无历史"与"指向原源文件 ⇒ 同一归档 + 新的 attempt",并明确旧回执不能作为修改后代码的证据。
45
+ - **v4 `paper` 字段可能被误读**:没有论文状态时该字段是**投影路径**;现在标注 `dirProjected`/`dirSource` 并声明读 `status` 无文件系统副作用。
46
+ - **成员可见材料的路径口径**:四个预设的成员材料补齐说明——文件工具按**会话 cwd** 解析路径,列出的相对路径需拼**项目根的绝对前缀**;计算产物请用回执的绝对字段 `receipt.scriptAbs`,或把 `receipt.cwd` 与 `receipt.scriptPath` 拼起来。
47
+ - **成员级调用只回一句"不存在"**:v4 现在返回错误码、当前编制与下一步建议;v2/v3 的决策与中断诊断同样给出 `code` 与 `next`。
48
+
49
+ ## 兼容性与迁移
50
+
51
+ - **破坏性变更:无。** 四套预设的参数默认值、数据格式、目录结构均未改变。
52
+ - **纯新增**:本版新增的响应字段都是**附加**的;遇到不认识的字段请忽略,不要据此报错。
53
+ - **迁移:无需迁移。**
54
+ - DSH 支撑窗口与 2.7.1 相同(见 `package.json` 的 `engines.dsh`)。
55
+
56
+ ## 已知限制
57
+
58
+ - **Octave / Julia 未随包提供**,在本次的验证机器上也未安装;相关模板与安装计划是静态校验过的,未经真机执行。
59
+ - **商业引擎(MATLAB / Maple / Wolfram)模板**仍需在持证机器上确认,默认标记为 `VERIFY`。
60
+ - **版本约束只按存在性检查**:具体版本求解仍由包管理器负责,本工具不解析约束。
61
+ - **插件无法强制禁网或限制写权限**:`subprocess` 通道没有策略槽位,需要宿主侧沙箱。
62
+ - **2.7.0 之前的发布说明仅提供中文**(英文历史索引见 `README.en.md`)。
63
+
64
+ ## 验证方式
65
+
66
+ - `node tests/run-tests.mjs` —— 全部通过(65 项:44 个套件 + 21 个灵敏度探针)。
67
+ - 三个数学契约守卫:`tests/audit-math-computation-parity.mjs`、`-contract.mjs`、`-sensitivity.mjs`。
68
+ - 真机验证(python 3.12.10 与 R 4.6.1):同一算式两边给出相同数值;原生路径与 `cli` 逃生口数字一致且 `scriptHash` 相同;超时 → `MATH_TIMEOUT`,语法错误 → `MATH_NONZERO_EXIT`(带 stderr 与回执),缺包 → `MATH_MISSING_PACKAGES`(不写回执目录),引擎警告 → 正常退出并保留 stderr。
69
+
70
+ ## 依赖
71
+
72
+ - **无新增运行时依赖**;DSH 支撑窗口不变。
@@ -0,0 +1,120 @@
1
+ # Release-notes template / 发布说明模板
2
+
3
+ This file defines the **single template** every `RELEASE-NOTES-<version>.md` (Chinese) and
4
+ `RELEASE-NOTES-<version>.en.md` (English) must follow. 本文件定义所有发布说明必须遵循的**唯一模板**。
5
+
6
+ - **File naming / 文件命名**:`RELEASE-NOTES-<version>.md`(中文)与 `RELEASE-NOTES-<version>.en.md`(English)。
7
+ Both files are required for every new release and both must be listed in `package.json#files`
8
+ (`tests/audit-market-metadata.test.mjs` enforces exactly that). 每个新版本**必须同时**有两份文件,且都列入
9
+ `package.json#files`(守卫 `tests/audit-market-metadata.test.mjs` 会检查)。
10
+ - **Heading order / 标题顺序**:the two languages use the **same order and the same section set**.
11
+ 中英两份必须**顺序一致、章节一致**(见下)。
12
+ - **Audience / 读者**:someone reading a changelog. 面向读变更日志的用户。
13
+ **Never** write internal project vocabulary (audit rounds, task/agent names, session IDs, "we found during
14
+ our testing") — state what changed for the user and how it is verified. 不得出现内部工作词汇(审计轮次、
15
+ 任务/成员名、会话编号、"我们在测试中发现"之类),只写对用户的变化与验证方式。
16
+
17
+ ## Required sections (in this order) / 必需章节(按此顺序)
18
+
19
+ | # | 中文标题 | English heading | Content / 内容要求 |
20
+ |---|---|---|---|
21
+ | 1 | `# dsh-vibe-math <version> — 发布说明` | `# dsh-vibe-math <version> — Release Notes` | Title with the exact version. 标题带准确版本号。 |
22
+ | 2 | `> 上一版本:<prev>。…` | `> Previous release: <prev>. …` | One paragraph: **what kind of release this is** (patch/minor), the headline changes, and an explicit compatibility sentence (defaults/formats/directory layout unchanged? migration needed?). 一段话:版本类型、要点、以及明确的兼容性结论(默认值/数据格式/目录结构是否变化、是否需要迁移)。 |
23
+ | 3 | `## 概述` | `## Overview` | 3–8 bullets, user-visible outcomes only; each bullet = one change. 3–8 条要点,只写用户可见的结果,一条一个变化。 |
24
+ | 4 | `## 新增` | `## Added` | New capabilities/fields/parameters. State the **exact** field or parameter names in backticks. 新能力/字段/参数,字段名一律用反引号写准确。 |
25
+ | 5 | `## 变更` | `## Changed` | Behaviour or wording changes (including documentation that now states something new). 行为或文案变化(含文档口径变化)。 |
26
+ | 6 | `## 修复` | `## Fixed` | Each fix: the user-visible symptom → the corrected behaviour. Include how it was reproduced/verified. 每条:用户可见症状 → 修正后的行为,并说明如何复现/验证。 |
27
+ | 7 | `## 兼容性与迁移` | `## Compatibility & Migration` | Explicit: breaking changes (usually "无 / None"), additive-only additions, migration steps, DSH support window. 明确列出破坏性变更(通常"无")、纯新增项、迁移步骤、DSH 支撑窗口。 |
28
+ | 8 | `## 已知限制` | `## Known Limitations` | Honest limits, including "unverified" and "not shipped". 如实写限制,包括"未验证"和"未随包提供"。 |
29
+ | 9 | `## 验证方式` | `## Verification` | The commands a reader can run (`node tests/run-tests.mjs …`) and what was verified on real engines, with versions. 读者可自行运行的命令,以及真机验证过的内容与版本号。 |
30
+ | 10 | `## 依赖` | `## Dependencies` | New/changed runtime dependencies (usually "无新增" / "None added") and the host (DSH) requirement. 新增/变化的运行时依赖(通常"无新增")与宿主(DSH)要求。 |
31
+
32
+ Sections with nothing to report keep their heading and say `无。` / `None.` — never delete a section, so
33
+ readers can rely on the structure. 无内容的章节**保留标题**并写"无。",不要删除章节,保证结构稳定。
34
+
35
+ ## Skeleton / 骨架
36
+
37
+ Chinese (`RELEASE-NOTES-<version>.md`):
38
+
39
+ ```markdown
40
+ # dsh-vibe-math <version> — 发布说明
41
+
42
+ > 上一版本:<prev>。本版是**补丁版 / 功能版**,<一句话要点>。四套预设的参数默认值、数据格式与目录结构**未变**,DSH 支撑窗口不变,**无需迁移**。
43
+
44
+ ## 概述
45
+ - …
46
+
47
+ ## 新增
48
+ - …
49
+
50
+ ## 变更
51
+ - …
52
+
53
+ ## 修复
54
+ - …
55
+
56
+ ## 兼容性与迁移
57
+ - 破坏性变更:无。
58
+ - 纯新增:…
59
+ - 迁移:无需迁移。
60
+
61
+ ## 已知限制
62
+ - …
63
+
64
+ ## 验证方式
65
+ - `node tests/run-tests.mjs` —— 全部通过(<N> 项)。
66
+ - …
67
+
68
+ ## 依赖
69
+ - 无新增运行时依赖;DSH 支撑窗口不变。
70
+ ```
71
+
72
+ English (`RELEASE-NOTES-<version>.en.md`):
73
+
74
+ ```markdown
75
+ # dsh-vibe-math <version> — Release Notes
76
+
77
+ > Previous release: <prev>. This is a **PATCH / FEATURE** release that <one-line headline>. Parameter defaults, data formats and the directory layout are **unchanged**, the DSH support window is unchanged, and **no migration is needed**.
78
+
79
+ ## Overview
80
+ - …
81
+
82
+ ## Added
83
+ - …
84
+
85
+ ## Changed
86
+ - …
87
+
88
+ ## Fixed
89
+ - …
90
+
91
+ ## Compatibility & Migration
92
+ - Breaking changes: none.
93
+ - Additive only: …
94
+ - Migration: none needed.
95
+
96
+ ## Known Limitations
97
+ - …
98
+
99
+ ## Verification
100
+ - `node tests/run-tests.mjs` — all green (<N> items).
101
+ - …
102
+
103
+ ## Dependencies
104
+ - No new runtime dependencies; the DSH support window is unchanged.
105
+ ```
106
+
107
+ ## Rules / 写作规则
108
+
109
+ 1. **Verify every claim against the code or docs before writing it.** If a behaviour is not in the shipped
110
+ bytes, it does not go in the notes. 每条声称在写之前都要对照代码/文档核实;没进包的行为不写。
111
+ 2. **Patch vs minor must be stated and justified** in the summary line; the version number itself is chosen
112
+ by the maintainer. 概述里写明是补丁版还是功能版并给出理由;版本号由维护者决定。
113
+ 3. **Name the exact API surface** (`field`, `next.reason`, parameter names) so users can grep for it.
114
+ 接口一律写准确名字,便于用户检索。
115
+ 4. **Do not machine-translate** the two versions: both are written by hand and kept structurally identical.
116
+ 两份都必须手写并保持结构一致,不用机翻。
117
+ 5. **English index**: every release also updates `README.en.md` (see below) so English readers can navigate
118
+ a history whose earlier entries are Chinese-only. 每个版本同时更新 `README.en.md`(英文历史索引)。
119
+ 6. **Historical files are frozen**: older notes are not reformatted retroactively; the template applies from
120
+ the next release onward. 历史文件不改写;模板自下一版本起生效。
@@ -1,154 +1,154 @@
1
- # 测试与脚本耗时基线(决定每次跑什么、怎么跑)
2
-
3
- > **为什么要写下来**:这套仓库的测试耗时极不均匀(一个套件 100 s,大多数不到 2 s;探针脚本要
4
- > 把同一套件跑十几遍)。不看数据就会犯两种错:要么每次都全量顺序跑(浪费 30 分钟),要么为了
5
- > 省时间去砍测例(降低覆盖)。**先看基线,再选策略**;每次跑完把实测时间跟本表对一下,偏差大
6
- > 就更新本表。
7
-
8
- ## 1. 怎么跑(并行是默认)
9
-
10
- ```bash
11
- node tests/run-tests.mjs # 全部套件 + 全部探针(tests/ 下每个 .mjs),并行(并发 = min(4, CPU 核数);命令都从**仓库根**执行)
12
- node tests/run-tests.mjs --only formal # 只跑名字含 formal 的项(套件与探针一起筛)
13
- node tests/run-tests.mjs --concurrency=6 # 手动指定并发
14
- node tests/run-tests.mjs --json # 机器可读汇总(含 skippedNeedsArgs / devCheckout)
15
- ```
16
-
17
- `run-tests.mjs` 的收集规则(Round B 起):`tests/` 下**每个** `.mjs` 都会被跑——
18
-
19
- - `*.test.mjs` 是**套件**;其余 `.mjs` 是**探针/审计**(灵敏度变异、注册面、自驱动守卫);
20
- - 只有登记在 runner 的 `NEEDS_ARGS` 里的脚本才会被跳过(当前只有 `audit-tool-exec.mjs`:它必须带
21
- `<preset-js> <tool-name>` 才能跑)。跳过项**每次运行都会打印出来**;在开发检出(存在 `.git`)里
22
- 该登记失效会**直接报错退出**,所以改名不可能悄悄把一条守卫踢出发布门禁;
23
- - 需要参数的变体登记在 `VARIANTS`:`audit-registration.mjs` 四个预设各跑一次(裸跑只查 v3)、
24
- `audit-prompt-invariants.mjs --self-probe`、以及 `audit-v3-registration-parity.mjs --self-probe`
25
- (这条**成功 = 退出码 1**:它注入真实变异并要求守卫变红,runner 用 `expectExit` 表达)。
26
-
27
- ### 1.1 随包发布 vs 仅仓库(`npm pack --dry-run --json`)
28
-
29
- `package.json` 的 `files` 只发 `tests/` 的一个**子集**(发布物共 **119** 个文件,其中 `tests/` **23** 项),
30
- 所以安装用户跑 `node tests/run-tests.mjs` 得到的是子集的结果——runner 会把缺失的跳过项打印出来,
31
- 不会静默少跑:
32
-
33
- - **随包(23 项)**:`run-tests.mjs`、`audit-formal-sensitivity.mjs`、`audit-persona-sensitivity.mjs`、
34
- `audit-prompt-invariants.mjs`、`audit-spec-traceability.mjs`、`audit-v5-integrity.mjs`、
35
- `audit-v5-sensitivity.mjs`、`selfdrive-v5.mjs`、`audit-math-computation-parity.mjs`、
36
- `audit-math-computation-contract.mjs`、`audit-math-computation-sensitivity.mjs`、
37
- `helpers/math-computation-fake-seam.mjs`;套件 **11** 个:`audit-installer-compat`、
38
- `audit-installer-policy`、`audit-persona-surface`、`audit-preset-rows`、`e2e-v5-round2`、
39
- `formal-verify-v2`、`formal-verify-v3`、`formal-verify-v4`、`formal-verify-v5`、`prompt-v5-integrity`、
40
- `math-computation-shared`。
41
- - **仅仓库(不发)**:其余 33 个套件(v2/v3/v4 的 e2e、`selfdrive-v3`/`v4`、v2/v3 修复探针、
42
- `math-computation-v2|v3|v4|v5`、`audit-fuzz-helpers` 之外的若干 `audit-*`……)与 7 个脚本(`audit-fuzz-helpers`、
43
- `audit-registration`、`audit-roundtrip-idempotence`、`audit-tool-exec`、
44
- `audit-v3-registration-parity`、`selfdrive-v3`、`selfdrive-v4`)。
45
- - 因此**完整门禁只能在开发检出里跑**;发布物里的子集是"用户可自查"的一部分,不是全部证据。
46
- (`audit-fuzz-helpers.mjs` 在 2.3.13 时曾随包发布;现在不在 `files` 里。)
47
-
48
- ## 2. 基线(本机:4 核 / Windows,实测)
49
-
50
- | 脚本 | 串行(sum) | 并行(wall) | 实测输出 |
51
- |---|---|---|---|
52
- | `tests/run-tests.mjs`(**65 项** = 44 套件 + 21 探针/变体) | ≈ 424 s | **≈ 121 s**(并发 4,speed-up x3.51) | `TOTAL 65 PASS 65 FAIL 0 (suites 44 · probes 21)`;实测 `wall 120.7s · sum 424.2s`,关键路径 = `e2e-v4-fixes`(≈ 98 s) |
53
- | `tests/audit-formal-sensitivity.mjs`(49 探针,自带并发 4;v2 12 / v3 12 / v4 12 / v5 13) | ≈ 1035 s | **260.7 s**(实测,x3.97) | 关键路径 = v2/v3 的 `require` 探针(各 ≈75 s);全 49 条按预期变红、0 问题 |
54
- | `tests/audit-v5-sensitivity.mjs`(39 探针,串行) | ≈ 101 s | — | 每条 = 一次被测套件重跑 |
55
- | `tests/audit-persona-sensitivity.mjs`(16 探针) | ≈ 4.4 s | — | 本身很快,不需要并行 |
56
- | `tests/audit-prompt-invariants.mjs`(157 条) | ≈ 1.9 s | — | 静态 |
57
- | `tests/audit-prompt-invariants.mjs --self-probe`(5 探针) | ≈ 7.4 s | — | 每个探针 = 一次自我重跑 |
58
- | `tests/audit-spec-traceability.mjs`(94 条) | ≈ 0.2 s | — | 静态 |
59
- | `tests/audit-v5-integrity.mjs` | ≈ 0.6 s | — | 静态审计(含扫描器自检) |
60
- | `tests/audit-registration.mjs`(4 个预设各一次) | ≈ 1.0 s | — | 裸跑只查 v3,所以 runner 跑四个变体 |
61
- | `tests/audit-v3-registration-parity.mjs`(+ `--self-probe`) | ≈ 0.3 s | — | 自探针**成功 = exit 1**(变异后守卫必须变红) |
62
- | `tests/prompt-v5-integrity.test.mjs` | ≈ 2.2 s | — | 虚拟时钟下生成 v5 语料(语料字节稳定;**stdout 里的会议成员顺序仍是运行间随机的**,只有落盘语料是逐字节确定的) |
63
- | `tests/e2e-v5-round2.test.mjs` | ≈ 3.2 s | — | v5 e2e(含本轮新增的"预置快照不被覆盖""命名研究所被读取""失败轮次"三节) |
64
- | `tests/host-failure-paths.test.mjs` | ≈ 6.3 s | — | 真实宿主的失败路径(`kind:'error'`、`/v4 set` 键校验、失败轮次不算进展) |
65
- | `tests/v4-mailbox-stall.test.mjs` | ≈ 7.1 s | — | `sendMessage` 拒绝后必须重投并唤醒(control + treatment 各一个 host) |
66
- | `tests/v2-fix-probes.test.mjs` | ≈ 8.6 s | — | v2 的 flat 等权均值 / ≥2 名验证者 / runShell 失败分支(26 条) |
67
- | `tests/v2-path-escape.test.mjs` | ≈ 2.2 s | — | 验证日志路径逃逸(7 条) |
68
- | `tests/v2-tool-cap.test.mjs` | ≈ 0.4 s | — | 能力表来自真实组合、*MaxToolCalls 只是提示(10 条) |
69
- | `tests/math-computation-v2.test.mjs` | ≈ 1.7 s | — | v2 接线:六参数/双注册层/回执/归档→编辑→重跑/跨会话隔离(含 mutant 说明在文件头) |
70
- | `tests/math-computation-v3.test.mjs` | ≈ 1.7 s | — | v3 同上(dual-layer + `TOOL_DESC` 描述 parity) |
71
- | `tests/math-computation-v4.test.mjs` | ≈ 2.5 s | — | v4:每会话一个模块实例 + 隔离断言 + `vibe_v4_set` 闭集 + 单点注册 |
72
- | `tests/math-computation-v5.test.mjs` | ≈ 1.4 s | — | v5:闭集 `vibe_v5_set`、研究所根回执、会话隔离(7 个 mutant) |
73
- | `tests/math-computation-shared.test.mjs` | ≈ 0.1 s | — | 共享模块契约(参数/失败码/argv/回执/归档/并发/override/路径守卫),走假 subprocess seam |
74
- | `tests/audit-math-computation-parity.mjs` | ≈ 0.1 s | — | 四份副本字节一致 + canonical 一致 + 两条安装线 + 描述符不变式(44 条) |
75
- | `tests/audit-math-computation-contract.mjs` | ≈ 0.2 s | — | 跨预设接线(含 set-schema **属性级**检查与 defaults 漂移检查) |
76
- | `tests/audit-math-computation-sensitivity.mjs` | ≈ 25 s | — | 21 个模块级变异,每条都要求具名断言变红(控制组必须绿) |
77
-
78
- > 上表 `run-tests` 的 `≈424 s / ≈121 s` 两列是 **65 项(44 套件 + 21 探针)** 时的实测(2026 年 math_computation
79
- > P1/P2a + 审计修复轮之后)。`audit-formal-sensitivity`(49 探针,实测 wall 260.7 s)与 `e2e-v4-fixes`(≈ 98 s)
80
- > 是两条最长的独立路径;两者都不在 `run-tests` 的默认集合里时,整轮 wall 由 `e2e-v4-fixes` 决定。
81
- > 数字**形状**(`TOTAL 65 … suites 44 · probes 21`)以 runner 每次运行的输出为准。
82
-
83
- 单套件耗时(并行时的关键路径按此排序):
84
-
85
- | 套件 | 耗时 | 备注 |
86
- |---|---|---|
87
- | `e2e-v4-fixes.test.mjs` | **≈ 104 s** | 9 个用例是**轮次采样**型(如 T13 采样 400 轮、T19/T25 多轮);时间 ≈ 轮数 × 框架自身的 40 ms 计时粒度 |
88
- | `formal-verify-v2.test.mjs` | **≈ 43 s** | 曾为 186 s:见 §3 |
89
- | `e2e-v3.test.mjs` | ≈ 21 s | |
90
- | `e2e-regression.test.mjs` | ≈ 14 s | |
91
- | `formal-verify-v3.test.mjs` | ≈ 13 s | |
92
- | `e2e-business.test.mjs` / `e2e-d9-d13.test.mjs` | ≈ 13 s | |
93
- | 其余套件 | ≤ 10 s | 其中绝大多数 < 2 s |
94
-
95
- > 优化前:全量回归 ≈ 5.5 min(串行,`formal-verify-v2` 单独 186 s);
96
- > 探针脚本 ≈ **38 min**(49 条串行,其中 12 条 × `formal-verify-v2` 162 s)。
97
- > 现在:**一套 `node tests/run-tests.mjs` ≈ 3.5 min 覆盖套件 + 探针**(探针单独跑仍是 ≈2.6 min)。
98
-
99
- ## 3. 已经做过的优化(别再重复踩)
100
-
101
- 1. **v2 套件 186 s → 32 s**(5.8×,断言数不变 261):
102
- - 插件用 `setInterval(..., 1000)` 轮询调度器,套件的每次 `tick()` 都得等满 1 秒;
103
- 套件现在**只把 `setInterval` 快进到 25 ms**(自己的 `sleep` 用 `setTimeout`,不受影响),
104
- 插件内部"该不该 tick"仍按真实 200 ms 下限判断,**生产代码零改动**;
105
- - `verifyWithDebate` 的 16 次循环**从不提前退出**(判据是 `autoDone` 之类永远不会发生的条件),
106
- 于是每次调用都烧满 16×1.3 s ≈ 21 s。现在按"连续 3 轮没有新 followup"提前退出。
107
- 2. **v4-fixes 的 12 个轮询循环加了"安静即停"**(105 s → 98 s):原判据
108
- `autoDone || running===false` 对活着的 run 永远不成立,循环只是空转;
109
- 现在连续 100 次无待答 followup 就停(`V4_IDLE_POLLS` 可调)。
110
- **再往下压就要砍采样深度了**——那 9 个慢用例(T13/T19/T22/T23/T25/T27/T2/T9/T20)是在
111
- 观察"多轮之后某个指令**没有**泄漏/重复",轮数是它们的不变式本体,不要再动。
112
- 3. **两个 runner 并行**(Round A):探针 38 min → 2.6 min(sum 612 s,wall 154.6 s,x3.96);
113
- 全量回归 5.5 min → 1.9 min(sum 221.5 s,wall 111.5 s,x1.99)。
114
- 4. **虚拟时钟**(`prompt-v5-integrity.test.mjs`):v5 研究所由 `ctx.timeout` + `Date.now()`
115
- 驱动,真实时钟下"哪个成员被心跳/会议唤醒"取决于负载与毫秒差 → **随包语料每跑一次都变**(无法 diff,
116
- 真实缺陷会被淹没)。套件现在把 `ctx.timeout` 接到**虚拟时钟**、`sleep(n)` 推进虚拟时间:
117
- 套件 **7–9 s → 1.7 s**,且语料连续 6 次运行**字节一致**。语料写入端另加**全序排序**
118
- (kind → owner → prompt),使文件成为"记录集合"的纯函数——只按 kind 排序时,同 kind 内仍会随
119
- 异步 drain 顺序变化(真实事故:两条会议提示词顺序互换)。
120
- > 想给别的套件套用同一手法前请注意:若套件的等待助手用 `Date.now()` 做**超时判据**、又用
121
- > `setInterval` 轮询(例如 `e2e-v4-fixes.test.mjs` 的 `waitFor`),冻结时钟会让判据永不超时;
122
- > 那种情况必须连**轮询定时器**一起虚拟化,不能只改 `sleep`。
123
- 5. **语料里的随机 id 也要归一化**(Round B,`formal-verify-v4.test.mjs`):v4 的
124
- `propose_task` 用 `Math.random` 造 `t-<8 位 hex>`,语料把 `[YOU CLAIMED TASK t-…]` 逐字写盘,
125
- 于是**每次跑测试都会改写随包语料**(`git status` 永远有 `prompt-corpus-v4/*`,且违反
126
- `AUDIT-CHECKLIST` §2.4"连续两次哈希相同")。`scrub()` 现在把它归一化成 `<TASKID>`,并断言
127
- "语料里既没有裸 id、也真的有 `<TASKID>`"。连续两次运行哈希相同(`d3381886…` / `e6c4e445…`)。
128
-
129
- ## 4. 并行安全(为什么可以并发)
130
-
131
- - 每个套件/探针都自建 `mkdtempSync` 工作区,互不共享状态;
132
- - **会写语料的套件必须给不同的语料目录**:`V2_CORPUS_DIR` / `V3_CORPUS_DIR` / `V4_CORPUS_DIR` /
133
- `V5_CORPUS_DIR`。探针 runner 为**每个探针**分配独立目录,否则同一套件的并发实例会互相覆盖语料;
134
- - `audit-v5-sensitivity.mjs` 现在**自己**把 `V5_CORPUS_DIR` 指向临时目录:被变异的插件绝不能把
135
- 自己的提示词倒进随包语料;
136
- - `audit-persona-sensitivity.mjs` 用 `PERSONA_ROOT` 指向变异副本,且在覆盖模式下**不写**语料;
137
- - `audit-formal-sensitivity.mjs` 同样给每个探针独立的 `V{2,3,4,5}_CORPUS_DIR`;
138
- - `audit-prompt-invariants.mjs --self-probe` 用 `PROMPT_INVARIANTS_MUTATE`(JSON `[rel, from, to]`)
139
- 在**内存里**变异一个文件并自我重跑,**不碰磁盘**,因此可与任何东西并发;
140
- 变异串里不要用 NUL 分隔(环境变量不允许 NUL 字节)。
141
-
142
- ## 5. 策略建议(按目的选最小代价的组合)
143
-
144
- | 目的 | 跑什么 | 预期 |
145
- |---|---|---|
146
- | 改了某个架构的插件 | `node tests/run-tests.mjs --only <vN>` + `node tests/audit-formal-sensitivity.mjs --only=vN` | 30 s – 3.5 min |
147
- | 改了提示词/人设 | `node tests/run-tests.mjs --only persona --only prompt` + `node tests/audit-persona-sensitivity.mjs` | ≈ 20 s |
148
- | **改了任何工具的参数 schema / 参数处理** | `node tests/run-tests.mjs --only audit-prompt-invariants --only formal` | ≈ 60 s(v2 套件占大头) |
149
- | 改了 `tests/` 下的 runner/守卫 | `node tests/run-tests.mjs`(**必须**:它现在同时跑套件与探针,任何一条守卫变红都会让门禁失败) | **≈ 3.5 min** |
150
- | 只想快速看提示词/文档有没有漂移 | `node tests/audit-prompt-invariants.mjs && node tests/audit-spec-traceability.mjs` | **< 3 s** |
151
- | 只想知道"快不快" | `node tests/run-tests.mjs --json` | 读 `wallSeconds` / `slowest` |
152
-
153
- **每次跑完都要看那几行 timing**:如果某个套件突然比基线慢很多,先怀疑新增的固定等待,
154
- 再怀疑它是否在等一个永远不会发生的条件(这正是 v2 套件 186 s 的成因)。
1
+ # 测试与脚本耗时基线(决定每次跑什么、怎么跑)
2
+
3
+ > **为什么要写下来**:这套仓库的测试耗时极不均匀(一个套件 100 s,大多数不到 2 s;探针脚本要
4
+ > 把同一套件跑十几遍)。不看数据就会犯两种错:要么每次都全量顺序跑(浪费 30 分钟),要么为了
5
+ > 省时间去砍测例(降低覆盖)。**先看基线,再选策略**;每次跑完把实测时间跟本表对一下,偏差大
6
+ > 就更新本表。
7
+
8
+ ## 1. 怎么跑(并行是默认)
9
+
10
+ ```bash
11
+ node tests/run-tests.mjs # 全部套件 + 全部探针(tests/ 下每个 .mjs),并行(并发 = min(4, CPU 核数);命令都从**仓库根**执行)
12
+ node tests/run-tests.mjs --only formal # 只跑名字含 formal 的项(套件与探针一起筛)
13
+ node tests/run-tests.mjs --concurrency=6 # 手动指定并发
14
+ node tests/run-tests.mjs --json # 机器可读汇总(含 skippedNeedsArgs / devCheckout)
15
+ ```
16
+
17
+ `run-tests.mjs` 的收集规则(Round B 起):`tests/` 下**每个** `.mjs` 都会被跑——
18
+
19
+ - `*.test.mjs` 是**套件**;其余 `.mjs` 是**探针/审计**(灵敏度变异、注册面、自驱动守卫);
20
+ - 只有登记在 runner 的 `NEEDS_ARGS` 里的脚本才会被跳过(当前只有 `audit-tool-exec.mjs`:它必须带
21
+ `<preset-js> <tool-name>` 才能跑)。跳过项**每次运行都会打印出来**;在开发检出(存在 `.git`)里
22
+ 该登记失效会**直接报错退出**,所以改名不可能悄悄把一条守卫踢出发布门禁;
23
+ - 需要参数的变体登记在 `VARIANTS`:`audit-registration.mjs` 四个预设各跑一次(裸跑只查 v3)、
24
+ `audit-prompt-invariants.mjs --self-probe`、以及 `audit-v3-registration-parity.mjs --self-probe`
25
+ (这条**成功 = 退出码 1**:它注入真实变异并要求守卫变红,runner 用 `expectExit` 表达)。
26
+
27
+ ### 1.1 随包发布 vs 仅仓库(`npm pack --dry-run --json`)
28
+
29
+ `package.json` 的 `files` 只发 `tests/` 的一个**子集**(发布物共 **119** 个文件,其中 `tests/` **23** 项),
30
+ 所以安装用户跑 `node tests/run-tests.mjs` 得到的是子集的结果——runner 会把缺失的跳过项打印出来,
31
+ 不会静默少跑:
32
+
33
+ - **随包(23 项)**:`run-tests.mjs`、`audit-formal-sensitivity.mjs`、`audit-persona-sensitivity.mjs`、
34
+ `audit-prompt-invariants.mjs`、`audit-spec-traceability.mjs`、`audit-v5-integrity.mjs`、
35
+ `audit-v5-sensitivity.mjs`、`selfdrive-v5.mjs`、`audit-math-computation-parity.mjs`、
36
+ `audit-math-computation-contract.mjs`、`audit-math-computation-sensitivity.mjs`、
37
+ `helpers/math-computation-fake-seam.mjs`;套件 **11** 个:`audit-installer-compat`、
38
+ `audit-installer-policy`、`audit-persona-surface`、`audit-preset-rows`、`e2e-v5-round2`、
39
+ `formal-verify-v2`、`formal-verify-v3`、`formal-verify-v4`、`formal-verify-v5`、`prompt-v5-integrity`、
40
+ `math-computation-shared`。
41
+ - **仅仓库(不发)**:其余 33 个套件(v2/v3/v4 的 e2e、`selfdrive-v3`/`v4`、v2/v3 修复探针、
42
+ `math-computation-v2|v3|v4|v5`、`audit-fuzz-helpers` 之外的若干 `audit-*`……)与 7 个脚本(`audit-fuzz-helpers`、
43
+ `audit-registration`、`audit-roundtrip-idempotence`、`audit-tool-exec`、
44
+ `audit-v3-registration-parity`、`selfdrive-v3`、`selfdrive-v4`)。
45
+ - 因此**完整门禁只能在开发检出里跑**;发布物里的子集是"用户可自查"的一部分,不是全部证据。
46
+ (`audit-fuzz-helpers.mjs` 在 2.3.13 时曾随包发布;现在不在 `files` 里。)
47
+
48
+ ## 2. 基线(本机:4 核 / Windows,实测)
49
+
50
+ | 脚本 | 串行(sum) | 并行(wall) | 实测输出 |
51
+ |---|---|---|---|
52
+ | `tests/run-tests.mjs`(**65 项** = 44 套件 + 21 探针/变体) | ≈ 424 s | **≈ 121 s**(并发 4,speed-up x3.51) | `TOTAL 65 PASS 65 FAIL 0 (suites 44 · probes 21)`;实测 `wall 120.7s · sum 424.2s`,关键路径 = `e2e-v4-fixes`(≈ 98 s) |
53
+ | `tests/audit-formal-sensitivity.mjs`(49 探针,自带并发 4;v2 12 / v3 12 / v4 12 / v5 13) | ≈ 1035 s | **260.7 s**(实测,x3.97) | 关键路径 = v2/v3 的 `require` 探针(各 ≈75 s);全 49 条按预期变红、0 问题 |
54
+ | `tests/audit-v5-sensitivity.mjs`(39 探针,串行) | ≈ 101 s | — | 每条 = 一次被测套件重跑 |
55
+ | `tests/audit-persona-sensitivity.mjs`(16 探针) | ≈ 4.4 s | — | 本身很快,不需要并行 |
56
+ | `tests/audit-prompt-invariants.mjs`(157 条) | ≈ 1.9 s | — | 静态 |
57
+ | `tests/audit-prompt-invariants.mjs --self-probe`(5 探针) | ≈ 7.4 s | — | 每个探针 = 一次自我重跑 |
58
+ | `tests/audit-spec-traceability.mjs`(94 条) | ≈ 0.2 s | — | 静态 |
59
+ | `tests/audit-v5-integrity.mjs` | ≈ 0.6 s | — | 静态审计(含扫描器自检) |
60
+ | `tests/audit-registration.mjs`(4 个预设各一次) | ≈ 1.0 s | — | 裸跑只查 v3,所以 runner 跑四个变体 |
61
+ | `tests/audit-v3-registration-parity.mjs`(+ `--self-probe`) | ≈ 0.3 s | — | 自探针**成功 = exit 1**(变异后守卫必须变红) |
62
+ | `tests/prompt-v5-integrity.test.mjs` | ≈ 2.2 s | — | 虚拟时钟下生成 v5 语料(语料字节稳定;**stdout 里的会议成员顺序仍是运行间随机的**,只有落盘语料是逐字节确定的) |
63
+ | `tests/e2e-v5-round2.test.mjs` | ≈ 3.2 s | — | v5 e2e(含本轮新增的"预置快照不被覆盖""命名研究所被读取""失败轮次"三节) |
64
+ | `tests/host-failure-paths.test.mjs` | ≈ 6.3 s | — | 真实宿主的失败路径(`kind:'error'`、`/v4 set` 键校验、失败轮次不算进展) |
65
+ | `tests/v4-mailbox-stall.test.mjs` | ≈ 7.1 s | — | `sendMessage` 拒绝后必须重投并唤醒(control + treatment 各一个 host) |
66
+ | `tests/v2-fix-probes.test.mjs` | ≈ 8.6 s | — | v2 的 flat 等权均值 / ≥2 名验证者 / runShell 失败分支(26 条) |
67
+ | `tests/v2-path-escape.test.mjs` | ≈ 2.2 s | — | 验证日志路径逃逸(7 条) |
68
+ | `tests/v2-tool-cap.test.mjs` | ≈ 0.4 s | — | 能力表来自真实组合、*MaxToolCalls 只是提示(10 条) |
69
+ | `tests/math-computation-v2.test.mjs` | ≈ 1.7 s | — | v2 接线:六参数/双注册层/回执/归档→编辑→重跑/跨会话隔离(含 mutant 说明在文件头) |
70
+ | `tests/math-computation-v3.test.mjs` | ≈ 1.7 s | — | v3 同上(dual-layer + `TOOL_DESC` 描述 parity) |
71
+ | `tests/math-computation-v4.test.mjs` | ≈ 2.5 s | — | v4:每会话一个模块实例 + 隔离断言 + `vibe_v4_set` 闭集 + 单点注册 |
72
+ | `tests/math-computation-v5.test.mjs` | ≈ 1.4 s | — | v5:闭集 `vibe_v5_set`、研究所根回执、会话隔离(7 个 mutant) |
73
+ | `tests/math-computation-shared.test.mjs` | ≈ 0.1 s | — | 共享模块契约(参数/失败码/argv/回执/归档/并发/override/路径守卫),走假 subprocess seam |
74
+ | `tests/audit-math-computation-parity.mjs` | ≈ 0.1 s | — | 四份副本字节一致 + canonical 一致 + 两条安装线 + 描述符不变式(44 条) |
75
+ | `tests/audit-math-computation-contract.mjs` | ≈ 0.2 s | — | 跨预设接线(含 set-schema **属性级**检查与 defaults 漂移检查) |
76
+ | `tests/audit-math-computation-sensitivity.mjs` | ≈ 25 s | — | 21 个模块级变异,每条都要求具名断言变红(控制组必须绿) |
77
+
78
+ > 上表 `run-tests` 的 `≈424 s / ≈121 s` 两列是 **65 项(44 套件 + 21 探针)** 时的实测(2026 年 math_computation
79
+ > P1/P2a + 审计修复轮之后)。`audit-formal-sensitivity`(49 探针,实测 wall 260.7 s)与 `e2e-v4-fixes`(≈ 98 s)
80
+ > 是两条最长的独立路径;两者都不在 `run-tests` 的默认集合里时,整轮 wall 由 `e2e-v4-fixes` 决定。
81
+ > 数字**形状**(`TOTAL 65 … suites 44 · probes 21`)以 runner 每次运行的输出为准。
82
+
83
+ 单套件耗时(并行时的关键路径按此排序):
84
+
85
+ | 套件 | 耗时 | 备注 |
86
+ |---|---|---|
87
+ | `e2e-v4-fixes.test.mjs` | **≈ 104 s** | 9 个用例是**轮次采样**型(如 T13 采样 400 轮、T19/T25 多轮);时间 ≈ 轮数 × 框架自身的 40 ms 计时粒度 |
88
+ | `formal-verify-v2.test.mjs` | **≈ 43 s** | 曾为 186 s:见 §3 |
89
+ | `e2e-v3.test.mjs` | ≈ 21 s | |
90
+ | `e2e-regression.test.mjs` | ≈ 14 s | |
91
+ | `formal-verify-v3.test.mjs` | ≈ 13 s | |
92
+ | `e2e-business.test.mjs` / `e2e-d9-d13.test.mjs` | ≈ 13 s | |
93
+ | 其余套件 | ≤ 10 s | 其中绝大多数 < 2 s |
94
+
95
+ > 优化前:全量回归 ≈ 5.5 min(串行,`formal-verify-v2` 单独 186 s);
96
+ > 探针脚本 ≈ **38 min**(49 条串行,其中 12 条 × `formal-verify-v2` 162 s)。
97
+ > 现在:**一套 `node tests/run-tests.mjs` ≈ 3.5 min 覆盖套件 + 探针**(探针单独跑仍是 ≈2.6 min)。
98
+
99
+ ## 3. 已经做过的优化(别再重复踩)
100
+
101
+ 1. **v2 套件 186 s → 32 s**(5.8×,断言数不变 261):
102
+ - 插件用 `setInterval(..., 1000)` 轮询调度器,套件的每次 `tick()` 都得等满 1 秒;
103
+ 套件现在**只把 `setInterval` 快进到 25 ms**(自己的 `sleep` 用 `setTimeout`,不受影响),
104
+ 插件内部"该不该 tick"仍按真实 200 ms 下限判断,**生产代码零改动**;
105
+ - `verifyWithDebate` 的 16 次循环**从不提前退出**(判据是 `autoDone` 之类永远不会发生的条件),
106
+ 于是每次调用都烧满 16×1.3 s ≈ 21 s。现在按"连续 3 轮没有新 followup"提前退出。
107
+ 2. **v4-fixes 的 12 个轮询循环加了"安静即停"**(105 s → 98 s):原判据
108
+ `autoDone || running===false` 对活着的 run 永远不成立,循环只是空转;
109
+ 现在连续 100 次无待答 followup 就停(`V4_IDLE_POLLS` 可调)。
110
+ **再往下压就要砍采样深度了**——那 9 个慢用例(T13/T19/T22/T23/T25/T27/T2/T9/T20)是在
111
+ 观察"多轮之后某个指令**没有**泄漏/重复",轮数是它们的不变式本体,不要再动。
112
+ 3. **两个 runner 并行**(Round A):探针 38 min → 2.6 min(sum 612 s,wall 154.6 s,x3.96);
113
+ 全量回归 5.5 min → 1.9 min(sum 221.5 s,wall 111.5 s,x1.99)。
114
+ 4. **虚拟时钟**(`prompt-v5-integrity.test.mjs`):v5 研究所由 `ctx.timeout` + `Date.now()`
115
+ 驱动,真实时钟下"哪个成员被心跳/会议唤醒"取决于负载与毫秒差 → **随包语料每跑一次都变**(无法 diff,
116
+ 真实缺陷会被淹没)。套件现在把 `ctx.timeout` 接到**虚拟时钟**、`sleep(n)` 推进虚拟时间:
117
+ 套件 **7–9 s → 1.7 s**,且语料连续 6 次运行**字节一致**。语料写入端另加**全序排序**
118
+ (kind → owner → prompt),使文件成为"记录集合"的纯函数——只按 kind 排序时,同 kind 内仍会随
119
+ 异步 drain 顺序变化(真实事故:两条会议提示词顺序互换)。
120
+ > 想给别的套件套用同一手法前请注意:若套件的等待助手用 `Date.now()` 做**超时判据**、又用
121
+ > `setInterval` 轮询(例如 `e2e-v4-fixes.test.mjs` 的 `waitFor`),冻结时钟会让判据永不超时;
122
+ > 那种情况必须连**轮询定时器**一起虚拟化,不能只改 `sleep`。
123
+ 5. **语料里的随机 id 也要归一化**(Round B,`formal-verify-v4.test.mjs`):v4 的
124
+ `propose_task` 用 `Math.random` 造 `t-<8 位 hex>`,语料把 `[YOU CLAIMED TASK t-…]` 逐字写盘,
125
+ 于是**每次跑测试都会改写随包语料**(`git status` 永远有 `prompt-corpus-v4/*`,且违反
126
+ `AUDIT-CHECKLIST` §2.4"连续两次哈希相同")。`scrub()` 现在把它归一化成 `<TASKID>`,并断言
127
+ "语料里既没有裸 id、也真的有 `<TASKID>`"。连续两次运行哈希相同(`d3381886…` / `e6c4e445…`)。
128
+
129
+ ## 4. 并行安全(为什么可以并发)
130
+
131
+ - 每个套件/探针都自建 `mkdtempSync` 工作区,互不共享状态;
132
+ - **会写语料的套件必须给不同的语料目录**:`V2_CORPUS_DIR` / `V3_CORPUS_DIR` / `V4_CORPUS_DIR` /
133
+ `V5_CORPUS_DIR`。探针 runner 为**每个探针**分配独立目录,否则同一套件的并发实例会互相覆盖语料;
134
+ - `audit-v5-sensitivity.mjs` 现在**自己**把 `V5_CORPUS_DIR` 指向临时目录:被变异的插件绝不能把
135
+ 自己的提示词倒进随包语料;
136
+ - `audit-persona-sensitivity.mjs` 用 `PERSONA_ROOT` 指向变异副本,且在覆盖模式下**不写**语料;
137
+ - `audit-formal-sensitivity.mjs` 同样给每个探针独立的 `V{2,3,4,5}_CORPUS_DIR`;
138
+ - `audit-prompt-invariants.mjs --self-probe` 用 `PROMPT_INVARIANTS_MUTATE`(JSON `[rel, from, to]`)
139
+ 在**内存里**变异一个文件并自我重跑,**不碰磁盘**,因此可与任何东西并发;
140
+ 变异串里不要用 NUL 分隔(环境变量不允许 NUL 字节)。
141
+
142
+ ## 5. 策略建议(按目的选最小代价的组合)
143
+
144
+ | 目的 | 跑什么 | 预期 |
145
+ |---|---|---|
146
+ | 改了某个架构的插件 | `node tests/run-tests.mjs --only <vN>` + `node tests/audit-formal-sensitivity.mjs --only=vN` | 30 s – 3.5 min |
147
+ | 改了提示词/人设 | `node tests/run-tests.mjs --only persona --only prompt` + `node tests/audit-persona-sensitivity.mjs` | ≈ 20 s |
148
+ | **改了任何工具的参数 schema / 参数处理** | `node tests/run-tests.mjs --only audit-prompt-invariants --only formal` | ≈ 60 s(v2 套件占大头) |
149
+ | 改了 `tests/` 下的 runner/守卫 | `node tests/run-tests.mjs`(**必须**:它现在同时跑套件与探针,任何一条守卫变红都会让门禁失败) | **≈ 3.5 min** |
150
+ | 只想快速看提示词/文档有没有漂移 | `node tests/audit-prompt-invariants.mjs && node tests/audit-spec-traceability.mjs` | **< 3 s** |
151
+ | 只想知道"快不快" | `node tests/run-tests.mjs --json` | 读 `wallSeconds` / `slowest` |
152
+
153
+ **每次跑完都要看那几行 timing**:如果某个套件突然比基线慢很多,先怀疑新增的固定等待,
154
+ 再怀疑它是否在等一个永远不会发生的条件(这正是 v2 套件 186 s 的成因)。