dsh-vibe-math 2.8.3 → 2.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/final-paper.md +5 -0
- package/docs/release-notes/README.en.md +1 -0
- package/docs/release-notes/README.md +1 -0
- package/docs/release-notes/RELEASE-NOTES-2.8.4.en.md +48 -0
- package/docs/release-notes/RELEASE-NOTES-2.8.4.md +48 -0
- package/package.json +5 -3
- package/tests/e2e-v5-round2.test.mjs +34 -0
- package/tests/v5-institute-fixes.mutants.mjs +8 -0
- package/vibe-math-v5/vibe-math-v5.js +7 -1
package/docs/final-paper.md
CHANGED
|
@@ -125,6 +125,11 @@
|
|
|
125
125
|
`consult = {messages: 0, meetings: 0}` 开始,**重启前的消息与会议不再计入**(这是设计,不是丢状态 ✗)。
|
|
126
126
|
因此 `paperEditor="office"` 在 `force` 之后必须**重新**征询;`V5_PAPER_CONSULT_REQUIRED` 的响应会**具名**说明
|
|
127
127
|
这一点(`restarted: true` + `forceReason`),不再让人靠猜。
|
|
128
|
+
- **会议何时会被放弃(看门狗)**:会议停滞超过 `2 × activityTimeoutMs`(默认 **240 s**)**且**没有任何被点名的成员
|
|
129
|
+
仍在进行中时,才由看门狗放弃 ✗;若仍有被点名的成员在飞,则宽限到 **3 倍**(默认 720 s)再放弃 —— 成员的**一整轮**
|
|
130
|
+
在真机上很容易超过软阈值,若此时就放弃,其发言只能退化成「会后补记」✗(实测一次真机运行出现 **1067** 次补记、
|
|
131
|
+
**863** 次定稿被拒 ✓)。放弃会写进纪要(`⚠ 本次会议因长时间无新发言而被放弃`)并在群聊具名一行 ✓;放弃**之后**
|
|
132
|
+
到达的发言不会被丢弃,而是作为「**会后补记**」追加进纪要 ✓(见 §7 上一条)。
|
|
128
133
|
|
|
129
134
|
## 8. LaTeX 检测、编译与降级
|
|
130
135
|
|
|
@@ -8,6 +8,7 @@ Chinese counterpart of this index is [`README.md`](./README.md) (中文索引).
|
|
|
8
8
|
|
|
9
9
|
| Version | Key change | Notes |
|
|
10
10
|
|---|---|---|
|
|
11
|
+
| 2.8.4 | Patch: v5's **meeting watchdog** no longer abandons a meeting while an ASKED member is still in flight (exempt within the soft bound; the 3× hard bound still closes it), so ordinary speeches return to the ordinary sections and "late notes" become an insurance policy again — before the fix one real run showed **1067** late notes and **863** refused finalisations. | [中文](./RELEASE-NOTES-2.8.4.md) · [English](./RELEASE-NOTES-2.8.4.en.md) |
|
|
11
12
|
| 2.8.3 | Patch: a speech arriving **after the meeting closed** is no longer dropped silently (it becomes a named "late note" in the minutes, which stay append-only); an office finalisation refused after a `force` restart now **explains why** (`restarted: true` + `forceReason`, stating that the counters restarted with the new paper and that a fresh consultation is required); the docs now state "`force` = a new paper". | [中文](./RELEASE-NOTES-2.8.3.md) · [English](./RELEASE-NOTES-2.8.3.en.md) |
|
|
12
13
|
| 2.8.2 | Patch: an explicit `paperLatexCommand` is now probed **alone**, so `triedPaths` no longer reports impossible paths of the form "known TeX root + absolute path"; v5's delivered `paper.md` / `paper.tex` now also **each state** the compile outcome (no engine detected / compilation failed), exactly once and without duplication on re-entry — matching v4 since 2.8.1. Both have real-host reproductions and named-red guards. | [中文](./RELEASE-NOTES-2.8.2.md) · [English](./RELEASE-NOTES-2.8.2.en.md) |
|
|
13
14
|
| 2.8.1 | Patch: v4's delivered `paper.md` and `paper.tex` now each state the compile outcome (no engine detected → tex+md only, or PDF compilation failed with tex/md kept), **exactly once** and idempotently — resolving known limitation #3 of the 2.8.0 notes; added `scripts/release-check.mjs`, which runs the pre-release checks as one command (version triple, section order of both notes, manifest registration, declared-but-missing = 0, repository-only files not shipped, no CRLF in the package). | [中文](./RELEASE-NOTES-2.8.1.md) · [English](./RELEASE-NOTES-2.8.1.en.md) |
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
| 版本 | 关键变化 | 说明 |
|
|
9
9
|
|---|---|---|
|
|
10
|
+
| 2.8.4 | 补丁:v5 **会议看门狗**不再在"被点名的成员仍在进行中"时放弃会议(软界内豁免、硬界 3 倍预算仍会放弃)⇒ 正常发言回到正常小节,「会后补记」退回为保险;修复前真机实测一次运行 **1067** 次补记、**863** 次定稿被拒。 | [中文](./RELEASE-NOTES-2.8.4.md) · [English](./RELEASE-NOTES-2.8.4.en.md) |
|
|
10
11
|
| 2.8.3 | 补丁:会议**收束后到达的发言**不再静默丢弃(作为具名「会后补记」写入纪要、只增不覆盖);`force` 重启后 `paperEditor="office"` 的定稿拒绝**说明原因**(新增 `restarted:true` + `forceReason`,并写明"计数随新论文重置、需重新征询");文档明确「`force` = 一张新论文」。 | [中文](./RELEASE-NOTES-2.8.3.md) · [English](./RELEASE-NOTES-2.8.3.en.md) |
|
|
11
12
|
| 2.8.2 | 补丁:显式 `paperLatexCommand` 改为**单独探测** ⇒ `triedPaths` 不再出现「已知 TeX 根 + 绝对路径」这类**不可能路径**;v5 交付的 `paper.md`/`paper.tex` 也**各自写明**编译结果(未检测到引擎/编译失败),恰好一次且重入不重复 ⇒ 与 2.8.1 的 v4 对齐。两处均有真机复现读数与具名红守卫。 | [中文](./RELEASE-NOTES-2.8.2.md) · [English](./RELEASE-NOTES-2.8.2.en.md) |
|
|
12
13
|
| 2.8.1 | 补丁:v4 交付的 `paper.md`/`paper.tex` 现在各自写明编译结果(未检测到引擎 ⇒ 只产出 tex+md,或 PDF 编译失败并保留 tex/md),**恰好一次**且幂等 ⇒ 2.8.0 说明里的「已知限制」第 3 条已解决;新增 `scripts/release-check.mjs` 把发布前逐项核对做成一条命令(版本三处一致/两份说明章节顺序/清单登记/声明缺失=0/开发专用文件不随包/包内无 CRLF)。 | [中文](./RELEASE-NOTES-2.8.1.md) · [English](./RELEASE-NOTES-2.8.1.en.md) |
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# dsh-vibe-math 2.8.4 — Release Notes
|
|
2
|
+
|
|
3
|
+
> Previous release: 2.8.3. This is a **patch release**: it fixes v5's **meeting watchdog**, which used to abandon a meeting while an ASKED member was still working — turning ordinary speeches into "late notes" and making `paperEditor="office"` finalisations fail again and again. Parameter names and 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
|
+
- A meeting is **no longer** abandoned before an ASKED member still in flight hands its speech in: such members may hold the meeting open up to **3×** the stall budget, after which the hard bound still closes it (a genuinely wedged turn must not wedge the whole meeting).
|
|
8
|
+
- The practical effect is that **ordinary speeches land in the ordinary sections again**: one real run before the fix showed **1067** "late notes" and **863** refused finalisations; with the fix, meetings actually collect their speakers and the "late note" path goes back to being an **insurance policy** rather than the norm.
|
|
9
|
+
- The `paperEditor="office"` gate therefore becomes satisfiable in practice (it requires at least one office message and one **recorded** meeting for this paper).
|
|
10
|
+
- The documentation now states when a meeting is abandoned, how the abandonment is named, and what happens to speeches that arrive **after** it.
|
|
11
|
+
|
|
12
|
+
## Added
|
|
13
|
+
|
|
14
|
+
- None. (Patch release: no new parameters, fields or tools.)
|
|
15
|
+
|
|
16
|
+
## Changed
|
|
17
|
+
|
|
18
|
+
- Meeting stall decision: within the soft bound (`2 × activityTimeoutMs`, default 240 s) the meeting is kept open as long as an **asked member is still in flight**; past the **3×** hard bound (default 720 s) it is still abandoned.
|
|
19
|
+
- `docs/final-paper.md` §7 now documents "when a meeting is abandoned" (soft/hard bounds and their relation to the "late note" path).
|
|
20
|
+
|
|
21
|
+
## Fixed
|
|
22
|
+
|
|
23
|
+
- Symptom: after members (including the **convener**) spoke in a meeting, the minutes only gained "late note" entries — one real run reached **1067** of them, and `paperEditor="office"` finalisations were refused by `V5_PAPER_CONSULT_REQUIRED` **863** times. Cause: the stall check measured only the time since the last INPUT and **ignored whether an asked member was still busy**; a member's turn on a real host frequently outlives the 240 s budget, so the meeting was abandoned by the watchdog and later speeches could only take the late-note path. Members that were asked and are still busy now hold the meeting open until the hard bound (3× the budget), so ordinary speeches return to the ordinary sections. Guards: `tests/e2e-v5-round2.test.mjs` (`★ [real1004-stall]`, a **source-level invariant** — this branch cannot be triggered deterministically inside the shipped suites, so the criterion is "source invariant + real-host re-test"), `tests/v5-institute-fixes.mutants.mjs` (**19/19** named reds).
|
|
24
|
+
|
|
25
|
+
## Compatibility & Migration
|
|
26
|
+
|
|
27
|
+
- Breaking changes: **none**.
|
|
28
|
+
- Additive only: no new fields (behaviour and documentation only).
|
|
29
|
+
- Migration: none needed.
|
|
30
|
+
- The DSH support window is unchanged (see `engines.dsh` in `package.json`).
|
|
31
|
+
|
|
32
|
+
## Known Limitations
|
|
33
|
+
|
|
34
|
+
- The **real-host** behaviour of the meeting watchdog can only be confirmed by a real-host re-test (inside the shipped suites the heartbeat delay is not controllable, so the branch cannot be triggered deterministically; the guard is therefore a **source-level invariant**, as stated in the test comments and the commit message).
|
|
35
|
+
- **TeX installed in a non-standard location is still not auto-discovered**: the default probe covers PATH and the documented common install roots.
|
|
36
|
+
- The shipped suites **do not cover host-level behaviour** (for example "the caller is dropped after an interrupt").
|
|
37
|
+
- **A root-agent question blocks the whole institute** (operational note, product unchanged): state the problem and acceptance criteria up front for unattended runs. See [`slv-playbook.md`](./slv-playbook.md) §5.
|
|
38
|
+
|
|
39
|
+
## Verification
|
|
40
|
+
|
|
41
|
+
- `node tests/run-tests.mjs` — all green (**106** items: 44 suites + 62 probes).
|
|
42
|
+
- `node scripts/release-check.mjs` — exits 0; after publishing, add `--registry` to compare the registry shasum with the local tarball.
|
|
43
|
+
- This release's fix: `node tests/e2e-v5-round2.test.mjs` (`★ [real1004-stall]`, measured `passed=436 failed=0`) and `node tests/v5-institute-fixes.mutants.mjs` (**19/19** named reds).
|
|
44
|
+
- Real-host re-check recipe: install the exact published version (`-Pin <version>`) and run a **trimmed** meeting + paper task (no research), then count "late notes" (1067 before the fix) and refused finalisations (863 before the fix) — both should drop sharply.
|
|
45
|
+
|
|
46
|
+
## Dependencies
|
|
47
|
+
|
|
48
|
+
- No new runtime dependencies; the DSH support window is unchanged.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# dsh-vibe-math 2.8.4 — 发布说明
|
|
2
|
+
|
|
3
|
+
> 上一版本:2.8.3。本版是**补丁版**:修正 v5 的**会议看门狗**——它此前会在"已被点名的成员仍在进行中"时就把会议放弃,导致成员的正常发言退化成「会后补记」,并让 `paperEditor="office"` 的定稿被反复拒绝。参数名与默认值、数据格式与目录结构**未变**,DSH 支撑窗口不变,**无需迁移**。
|
|
4
|
+
|
|
5
|
+
## 概述
|
|
6
|
+
|
|
7
|
+
- 会议**不再**在"被点名、且仍在进行中"的成员交回发言之前被放弃:这类成员最多把会议续命到停滞预算的 **3 倍**,超过硬界才放弃(真正卡死的一轮仍不能拖住整场会议)。
|
|
8
|
+
- 结果是**正常发言回到正常小节**:真机实测修复前一次运行出现 **1067** 次「会后补记」、**863** 次定稿被拒;修复后会议能真正收齐发言,「会后补记」退回为**保险**而非常态。
|
|
9
|
+
- `paperEditor="office"` 的定稿闸门因此更容易被真正满足(它要求本张论文至少有 1 条所办消息与 1 次**记录在案**的会议)。
|
|
10
|
+
- 文档写明会议何时会被放弃、放弃如何具名、以及放弃**之后**到达的发言如何处置。
|
|
11
|
+
|
|
12
|
+
## 新增
|
|
13
|
+
|
|
14
|
+
- 无。(本版为修复版:没有新增参数、字段或工具。)
|
|
15
|
+
|
|
16
|
+
## 变更
|
|
17
|
+
|
|
18
|
+
- 会议停滞判定:软界(`2 × activityTimeoutMs`,默认 240 s)内,只要仍有**被点名的成员在进行中**就不放弃;超过 **3 倍**(默认 720 s)的硬界则照旧放弃。
|
|
19
|
+
- `docs/final-paper.md` §7 增补"会议何时会被放弃"的口径(含软界/硬界与「会后补记」的关系)。
|
|
20
|
+
|
|
21
|
+
## 修复
|
|
22
|
+
|
|
23
|
+
- 症状:成员(含**召集人**)在会议里发言后,纪要里却只留下「会后补记」条目;一次真机运行累计 **1067** 次补记,并且 `paperEditor="office"` 的定稿被 `V5_PAPER_CONSULT_REQUIRED` 拒绝 **863** 次。原因:会议停滞只按"最后一次发言"计时,**不看被点名的成员是否仍在忙**;真机上成员的一整轮常常超过 240 s 的预算,于是会议在看门狗手里被放弃,随后到达的发言只能走补记通道。现在"被点名且仍在忙"的成员会把放弃推迟到硬界(3 倍预算),正常发言因此回到会议的正常小节。守卫:`tests/e2e-v5-round2.test.mjs`(`★ [real1004-stall]`,**源码级不变量**:该分支的真机行为无法在随包套件里确定性触发,故判据是"源码不变量 + 真机复测")、`tests/v5-institute-fixes.mutants.mjs`(**19/19** 具名红)。
|
|
24
|
+
|
|
25
|
+
## 兼容性与迁移
|
|
26
|
+
|
|
27
|
+
- 破坏性变更:**无**。
|
|
28
|
+
- 纯新增:无新增字段(仅行为与文档变化)。
|
|
29
|
+
- 迁移:无需迁移。
|
|
30
|
+
- DSH 支撑窗口不变(见 `package.json` 的 `engines.dsh`)。
|
|
31
|
+
|
|
32
|
+
## 已知限制
|
|
33
|
+
|
|
34
|
+
- 会议看门狗分支的**真机**行为只能由真机复测确认(随包套件里心跳延时不可控 ⇒ 该分支不能确定性触发;因此守卫是**源码不变量**,这一点已在测试注释与提交信息里写明)。
|
|
35
|
+
- **非标准位置的 TeX 仍不会被自动发现**:默认探测只覆盖 PATH 与文档化的常见安装根。
|
|
36
|
+
- 随包套件**不覆盖宿主层行为**(例如"中断后调用方被丢弃")。
|
|
37
|
+
- **根代理提问会阻塞整所流程**(运维注意项,不改产品):长跑时请把问题与验收条件一次说清。详见 [`slv-playbook.md`](./slv-playbook.md) §5。
|
|
38
|
+
|
|
39
|
+
## 验证方式
|
|
40
|
+
|
|
41
|
+
- `node tests/run-tests.mjs` —— 全部通过(**106** 项:44 套件 + 62 探针)。
|
|
42
|
+
- `node scripts/release-check.mjs` —— 退出 0;发布后加 `--registry` 比对线上 shasum 与本地 tarball。
|
|
43
|
+
- 本版修复:`node tests/e2e-v5-round2.test.mjs`(`★ [real1004-stall]`,实测 `passed=436 failed=0`)与 `node tests/v5-institute-fixes.mutants.mjs`(**19/19** 具名红)。
|
|
44
|
+
- 真机复测配方:用 registry 上的精确版本(`-Pin <version>`)跑一个**精简**会议+论文任务(跳过研究),统计「会后补记」次数(修复前 1067 次)与定稿被拒次数(修复前 863 次)应显著下降。
|
|
45
|
+
|
|
46
|
+
## 依赖
|
|
47
|
+
|
|
48
|
+
- 无新增运行时依赖;DSH 支撑窗口不变。
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-vibe-math",
|
|
3
3
|
"description": "Multi-agent mathematical problem-solving & verification frameworks for DeepSeek Harness — FOUR agent presets in one install: vibe-math-v2 (probability-driven, classic: qs.json + Propos knowledge base + explorer→solver→review/debate verdict), vibe-math-v3 (THIRD-generation, classic: paper-style Markdown knowledge base with Problems/Progress/Propos/Methods/Verified + planner-agent scheduling that decides the next N actions + universal theory/method invention library + agents write their own Markdown directly via a per-file write lock), and vibe-math-v4 (FOURTH-generation: persistent self-organizing resident subagents that message & meet to decide all tasks, verify only by unanimous consensus, /compact at a context threshold, and stop only when all agree the problem is solved), and vibe-math-v5 (FIFTH-generation research institute: an academician as the organizational centre who decomposes and ASSIGNS work and chairs meetings; permanent researchers who hold the vote and may hire/fire their own temp workers; temp workers with no vote; a group chat and meetings; a durable per-recipient mailbox; a compare-and-set task DAG; and a boolean m-vote consensus rule where an object enters Verified/ only when at least m voting members agree AND every one of them returns exactly 1 or exactly 0). Installing this bundle auto-installs all four presets (v1 was removed at v2.0.0). Each preset also writes a FINAL PAPER by default when its run concludes — and does so BEFORE the run is marked complete: on v4/v5 the team co-authors its parts, merges them, cross-reviews, and the editor named by paperEditor finalises; the output is Paper/<run or institute id>/{paper.md,paper.tex,paper.pdf when a LaTeX engine is detected,paper.meta.json,paper.log.md} (params finalPaper/paperFormat/paperLanguage/paperCompilePdf/paperLatexCommand, plus paperEditor on v4/v5; see docs/final-paper.md).",
|
|
4
|
-
"version": "2.8.
|
|
4
|
+
"version": "2.8.4",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
7
7
|
"node": "^22.19.0 || >=24.0.0",
|
|
@@ -211,7 +211,9 @@
|
|
|
211
211
|
"docs/release-notes/RELEASE-NOTES-2.8.2.md",
|
|
212
212
|
"docs/release-notes/RELEASE-NOTES-2.8.2.en.md",
|
|
213
213
|
"docs/release-notes/RELEASE-NOTES-2.8.3.md",
|
|
214
|
-
"docs/release-notes/RELEASE-NOTES-2.8.3.en.md"
|
|
214
|
+
"docs/release-notes/RELEASE-NOTES-2.8.3.en.md",
|
|
215
|
+
"docs/release-notes/RELEASE-NOTES-2.8.4.md",
|
|
216
|
+
"docs/release-notes/RELEASE-NOTES-2.8.4.en.md"
|
|
215
217
|
],
|
|
216
218
|
"license": "MIT",
|
|
217
219
|
"keywords": [
|
|
@@ -241,7 +243,7 @@
|
|
|
241
243
|
},
|
|
242
244
|
"minVersion": "0.1.2-alpha.4",
|
|
243
245
|
"testedVersion": "0.2.0-rc.2",
|
|
244
|
-
"compatNote": "v2.8.
|
|
246
|
+
"compatNote": "v2.8.4 补丁版:修 v5 的会议看门狗。① 停滞判定不再只看\"最后一次发言\":软界(2 × activityTimeoutMs,默认 240 s)内只要仍有**被点名的成员在进行中**就不放弃会议,超过硬界(3 倍,默认 720 s)照旧放弃 —— 看门狗保留牙齿,真正卡死的一轮不会拖住整场会议。② 效果:成员(含召集人)的正常发言回到会议正常小节,「会后补记」退回为保险;修复前真机实测一次运行出现 1067 次补记、863 次 paperEditor=\"office\" 定稿被 V5_PAPER_CONSULT_REQUIRED 拒绝。③ docs/final-paper.md §7 写明会议何时被放弃、如何具名、以及放弃后到达的发言如何处置。参数名与默认值、数据格式与目录结构均未变;DSH 支撑窗口不变;无需迁移。",
|
|
245
247
|
"compatibility": {
|
|
246
248
|
"dshReleases": {
|
|
247
249
|
"0.1.2-alpha.4": "compatible",
|
|
@@ -1495,6 +1495,40 @@ console.log('\n[27] fake LaTeX compiler: repair path and persistent-failure degr
|
|
|
1495
1495
|
'★ [real1004-minutes] a speech arriving after the meeting closed is appended as a late note, never dropped silently')
|
|
1496
1496
|
assert(after.includes('### '), 'the earlier speeches are still in the minutes (append-only, never clobbered)')
|
|
1497
1497
|
}
|
|
1498
|
+
// real1004-stall (found on a real host with 2.8.3): the meeting watchdog measured "stall" from the last INPUT and
|
|
1499
|
+
// ignored whether an ASKED member was still busy. A member's turn easily outlives the budget on a real host, so
|
|
1500
|
+
// meetings were abandoned mid-turn and the speeches could only land as "late notes" (that run: 1067 late notes
|
|
1501
|
+
// and 863 refused office finalisations). A meeting must survive while an asked speaker is in flight.
|
|
1502
|
+
{
|
|
1503
|
+
const hs = makeHost({ pluginModule })
|
|
1504
|
+
await hs.callTool('vibe_v5_start', { problem: PROBLEM, researcherCount: 1 })
|
|
1505
|
+
await hs.settleSpawns()
|
|
1506
|
+
await hs.callTool('vibe_v5_set', { activityTimeoutMs: 300 }) // soft stall = 600 ms, hard bound = 1800 ms
|
|
1507
|
+
const mts = await hs.callTool('vibe_v5_meeting', { agenda: 'real1004-stall:被点名的成员仍在忙', kind: 'sync' })
|
|
1508
|
+
const midS = mts && mts.meeting
|
|
1509
|
+
assert(!!midS, 'precondition: the meeting is convened (' + JSON.stringify(mts).slice(0, 110) + ')')
|
|
1510
|
+
// acad is asked and NOT answered, so it stays BUSY. Nobody submits an input, so `lastInputAt` keeps ageing.
|
|
1511
|
+
// NOTE (why this is a SOURCE-level invariant): the watchdog branch runs from a heartbeat whose armed delay is
|
|
1512
|
+
// not controllable from this harness (the plugin arms `ctx.timeout` with delays up to tens of seconds), so a
|
|
1513
|
+
// runtime assertion here cannot be made to FAIL on the unfixed code — it would be a vacuous guard. The
|
|
1514
|
+
// behaviour is instead pinned by (a) this source invariant and (b) the real-host re-test, which is the
|
|
1515
|
+
// acceptance criterion of the board task (measured there: 1067 late notes before the fix).
|
|
1516
|
+
const wA = await hs.peekWakeOf('acad', 3000)
|
|
1517
|
+
assert(!!wA, 'precondition: a member was asked to speak (so it is busy) while no input has arrived')
|
|
1518
|
+
await sleep(900) // past the SOFT bound, inside the hard one
|
|
1519
|
+
const mpathS = join(hs.WS, 'VibeMath', 'Projects', 'default', 'Institutes', 'institute', 'Shared', 'Meetings', midS + '.md')
|
|
1520
|
+
assert(!readFileSync(mpathS, 'utf8').includes('因长时间无新发言而被放弃'),
|
|
1521
|
+
'no input has arrived yet, so nothing may close this meeting: ' + readFileSync(mpathS, 'utf8').slice(0, 160))
|
|
1522
|
+
hs.fireEnd(wA.childId, { input: 'real1004-stall:我被点名后仍在忙,现在交回我的发言。', contextPct: 20 })
|
|
1523
|
+
await sleep(300)
|
|
1524
|
+
const docS = readFileSync(mpathS, 'utf8')
|
|
1525
|
+
assert(docS.includes('### acad') && !docS.includes('(会后补记'),
|
|
1526
|
+
'a speech from an ASKED member lands in the NORMAL section (never as a late note)')
|
|
1527
|
+
const v5src = readFileSync(PLUGIN, 'utf8') // PLUGIN points at the mutated COPY when a family runs this suite
|
|
1528
|
+
assert(v5src.includes('const inFlight = meeting.order.some((id) => busy.has(id))') &&
|
|
1529
|
+
v5src.includes('if (stale >= recoverStallMs() && (!inFlight || stale >= recoverStallMs() * 3)) {'),
|
|
1530
|
+
'★ [real1004-stall] the meeting watchdog exempts ASKED-but-busy speakers up to a hard bound (a real host abandoned meetings mid-turn: 1067 late notes, 863 refused finalisations)')
|
|
1531
|
+
}
|
|
1498
1532
|
|
|
1499
1533
|
// ---------- 28. office-only surface + id normalisation ----------
|
|
1500
1534
|
console.log('\n[28] the final-paper surface is office-only and its directory id cannot escape Paper/')
|
|
@@ -235,6 +235,14 @@ const FAMILIES = [
|
|
|
235
235
|
to: 'const restarted = false',
|
|
236
236
|
expect: /\[real1004-consult\] an office finalisation after a force restart NAMES the reset/,
|
|
237
237
|
},
|
|
238
|
+
{
|
|
239
|
+
// real1004-stall: the meeting must NOT be abandoned while an asked speaker is still in flight — doing so is
|
|
240
|
+
// what turned ordinary speeches into "late notes" on a real host (1067 of them).
|
|
241
|
+
name: 'real1004-stall: the meeting is abandoned while an asked member is still busy',
|
|
242
|
+
from: 'if (stale >= recoverStallMs() && (!inFlight || stale >= recoverStallMs() * 3)) {',
|
|
243
|
+
to: 'if (stale >= recoverStallMs()) {',
|
|
244
|
+
expect: /\[real1004-stall\] the meeting watchdog exempts ASKED-but-busy speakers/,
|
|
245
|
+
},
|
|
238
246
|
]
|
|
239
247
|
let red = 0
|
|
240
248
|
for (const f of FAMILIES) { const ok = runFamily(f); if (ok) red++ }
|
|
@@ -5040,7 +5040,13 @@ export function apply(ctx) {
|
|
|
5040
5040
|
// without a heartbeat nothing would retry it once the lock clears.
|
|
5041
5041
|
if (finalizeLock) { armHeartbeat(); return }
|
|
5042
5042
|
const stale = now() - Number(meeting.lastInputAt || meeting.startedAt || now())
|
|
5043
|
-
|
|
5043
|
+
// real1004-stall: a member's TURN can outlive the stall budget on a real host, and the old check ignored
|
|
5044
|
+
// that — the meeting was abandoned while an ASKED member was still busy, so its speech could only land as
|
|
5045
|
+
// a "late note" (measured on one real run: 1067 late notes and 863 refused office finalisations). Never
|
|
5046
|
+
// abandon while an asked speaker is in flight — but keep the watchdog's teeth: past 3× the budget even an
|
|
5047
|
+
// in-flight member no longer holds the meeting open (a genuinely wedged turn must not wedge the meeting).
|
|
5048
|
+
const inFlight = meeting.order.some((id) => busy.has(id))
|
|
5049
|
+
if (stale >= recoverStallMs() && (!inFlight || stale >= recoverStallMs() * 3)) {
|
|
5044
5050
|
const abandoned = meeting
|
|
5045
5051
|
meeting = null
|
|
5046
5052
|
await appendMeetingTail(abandoned, '⚠ 本次会议因长时间无新发言而被放弃(看门狗);团队回到自组织推进。')
|