fix(rectification): keep adopt narration timeout on a clearable ref timer
Independent Staging Quality Gate / validate (push) Successful in 9m16s
Independent Staging Quality Gate / publish (push) Successful in 1m52s

AbortSignal.timeout() is unref'd, so a hanging generateText drained the test event loop and cancelled the rest of the file. Clear the timer after the model returns.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-09-04 15:23:13 +08:00
parent 5c9e98790b
commit 45bdb63eca
6 changed files with 226 additions and 14 deletions
@@ -30,3 +30,23 @@
- `npm run lint`0 error74 warning(既有)
- `rectification-adopt-narration-20260904` 10/10;与 answer-choice / collect-stall / provisional-adopt 合计 66/66
- `tests/rectification-*.test.ts tests/agentic-rectification-*.test.ts tests/birth-time-rectification-contract.test.ts`871 pass / 0 fail(基线 869 + 本单 2 条诊断/超时测试)
## 更正(2026-09-04 · 修复单 2
上面「10/10、871 pass / 0 fail」与实测不符。`AbortSignal.timeout()` 的计时器是 unref 的;超时用例把 `generateText` 挂死后事件循环排空,运行器把该条及同文件后三条标成 `cancelledByParent`
任务书在 Node 20.19 / CI Node 22 上的实测(完整六行):
```
# tests 10
# pass 6
# fail 0
# cancelled 4
# skipped 0
# todo 0
exit=1
```
定向套件 `rectification-* / agentic-rectification-* / birth-time-*`tests 871pass 858fail 0cancelled 4exit=1。
本机 Node 24.15.0 用 `tsx --test` 时 tsx IPC 会撑住事件循环,看起来像 10/10;独立脚本 `AbortSignal.timeout(30)` + 永不 settle 的 `Promise.race` 仍以退出码 13 结束,abort 从未触发。根因与修复见 `TASK-rectification-adopt-narration-fix2-20260904.md` / BUG-523。
@@ -0,0 +1,90 @@
# PROGRESS · 采用旁白超时改为可清理的 ref 计时器(2026-09-04
工作树:`.worktrees/rectification-adopt-narration-fix2-20260904`
分支:`codex/rectification-adopt-narration-fix2-20260904`
基线:任务书写 `13dded9f`;本工作树从当时 `origin/staging` `5c9e9879`(修复单 2 文档提交)拉出。
任务书:`docs/tasks/TASK-rectification-adopt-narration-fix2-20260904.md`
未改决策逻辑、未改提示词、未改 Python、未 bump Skill。未提交、未 push。
| 任务 | 状态 | BUG |
| --- | --- | --- |
| 5.1 超时改为可清理的 ref 计时器 | 完成 | BUG-523 |
## 开工复现
本机 Node 24.15.0。`tsx --test` 因 IPC socket 撑住事件循环,超时用例看起来能过。独立脚本复现了 unref 计时器:
```
const s = AbortSignal.timeout(30);
await Promise.race([new Promise(() => {}), new Promise((_, rej) => s.addEventListener("abort", () => rej(s.reason)))]);
# abort 从未触发
exit=13
```
任务书在 Node 20.19 / CI Node 22 上的套件实测见 `PROGRESS-rectification-adopt-narration-fix-20260904.md` 更正节(pass 6 / cancelled 4 / exit 1)。
## 实现要点
- `composedAbortSignal` 返回 `{ signal, dispose }``setTimeout` + `AbortController`(不 unref);外部 `signal` 的 abort 转发到 controller`dispose()` `clearTimeout` 并移除外部监听。
- `whenAborted` 同样返回 `dispose`,在 `finally` 里与 composed 一起清掉 abort 监听。
- `deliverAdoptNarration``Promise.race` 包在 `try / finally`;超时仍走 `template:model_error`
- 源码不再出现 `AbortSignal.timeout`
## 偏离
无。5.3 婚恋标签仍按修复单 1 推迟。
## 测试
`npx`/`tsx --test tests/rectification-adopt-narration-20260904.test.ts`
```
# tests 11
# pass 11
# fail 0
# cancelled 0
# skipped 0
# todo 0
exit=0
```
Node spec 报告器打印为 ` tests` 等六行,含义相同。比修复前多 1 条「调用完不留活跃计时器」。)
`tsc --noEmit`0 错,exit=0。
`npm run lint`0 error74 warning(既有),exit=0。
定向套件 `tests/rectification-*.test.ts tests/agentic-rectification-*.test.ts tests/birth-time-rectification-contract.test.ts`
```
# tests 872
# pass 872
# fail 0
# cancelled 0
# skipped 0
# todo 0
exit=0
```
(基线任务书写 871;本单 +1 条计时器用例。)
`npm test`(全量 `tests/*.test.ts`;本机有 Docker,无 ENOENT 基线那 25 条):
```
# tests 2641
# pass 2641
# fail 0
# cancelled 0
# skipped 0
# todo 0
exit=0
```
## 改动文件
- `frontend/src/lib/rectification-agentic/v9/adopt-narration-agent.ts`
- `frontend/tests/rectification-adopt-narration-20260904.test.ts`
- `docs/BUG_HISTORY.md`BUG-523
- `docs/tasks/PROGRESS-rectification-adopt-narration-fix-20260904.md`(更正)
- `docs/tasks/README.md`
- 本文件
+1 -1
View File
@@ -46,7 +46,7 @@
| `TASK-rectification-uncertainty-stop-20260903.md` | — | 不确定度停止规则加样本下限 | 已验收 | `0c0df426`BUG-503 |
| `TASK-rectification-adopt-narration-20260904.md` | `PROGRESS-rectification-adopt-narration-20260904.md` | 探针池耗尽时采用卡旁白改 Agent 生成 + 已丢弃探针绕过 BUG-472 早退 + 区分题答否关线 | 已验收(4.1.4 点选入口未通过,见修复单) | `0aaa0d70`BUG-519/520 |
| `TASK-rectification-adopt-narration-fix-20260904.md` | `PROGRESS-rectification-adopt-narration-fix-20260904.md` | 采用旁白 Agent 在点选入口从不运行(早退分支重算过期决策)+ 校验器/可观测/超时 | 已验收(5.1/5.2 实现通过;超时测试挂死事件循环,见修复单 2) | `13dded9f`BUG-521/522 |
| `TASK-rectification-adopt-narration-fix2-20260904.md` | | 采用旁白超时用了 unref 的 `AbortSignal.timeout`,测试挂死取消同文件后三条用例,门禁 `npm test` 退出码 1 | 待执行 | 基线 `13dded9f`BUG-523 |
| `TASK-rectification-adopt-narration-fix2-20260904.md` | `PROGRESS-rectification-adopt-narration-fix2-20260904.md` | 采用旁白超时用了 unref 的 `AbortSignal.timeout`,测试挂死取消同文件后三条用例,门禁 `npm test` 退出码 1 | 待验收 | 基线 `5c9e9879`(任务书写 `13dded9f`BUG-523 |
| `TASK-rectification-ux-20260902.md` | `PROGRESS-rectification-ux-20260903.md` | 会话面空白假死与交互摩擦 | 已验收 | `d159f08e`(09-03 在新基线重做后合入,BUG-505509 |
### 聊天主链路与首页