Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0155nFCgCHtoA7jhSDGmZmMu
6.6 KiB
修复单 2 · 采用旁白超时测试挂死事件循环,拖垮同文件后三条用例(2026-09-04)
基线:origin/staging 13dded9f(TASK-rectification-adopt-narration-fix-20260904.md 的实现)。本单只改 adopt-narration-agent.ts 的超时实现与对应进度记录,不动决策逻辑、不动提示词。
0. 验收结论(对照修复单 1)
| 项 | 结论 | 证据 |
|---|---|---|
5.1 早退分支用本轮决策;三条调用方传 decision;facts / 模板用合成 receipt |
通过 | persistNextInterviewAfterChoice 函数体无 decideFromDossier(;dossierWithCurrentInference;点选用例改为点选前 dossier(revision 5、23/16/7),断言模型 1 次、facts 05:00 / 21/18/9 / ready_to_adopt;非法输出时模板范围来自本轮决策 |
5.2 提示词「不要出现」;诊断枚举 adopt_narration=;8s 超时 |
通过(实现)/ 未通过(测试,见 §1) | 提示词与校验器同口径;deliverAdoptNarration 返回 adopt_narration,console.info 不含模型原文;四种结果各有断言 |
5.3 stopFactsFromDropped 婚恋标签 |
推迟(允许) | 进度记录已写明 |
| BUG-521 / BUG-522 | 通过 | 无案例 ID、无用户资料;复发链接 BUG-440 |
CHANGELOG、docs/testing 清单 |
通过 | 点选入口列为优先手测项 |
| tsc / lint | 通过 | tsc 0 错;lint 0 error 74 warning(既有) |
| 定向套件 | 未通过 | rectification-* / agentic-rectification-* / birth-time-*:871 条,pass 858,fail 0,cancelled 4,进程退出码 1 |
1. 事故实证(P1 · 超时测试挂死)
adopt-narration-agent.ts:
function composedAbortSignal(signal, timeoutMs) {
const timeout = AbortSignal.timeout(timeoutMs);
return signal ? AbortSignal.any([signal, timeout]) : timeout;
}
Node 的 AbortSignal.timeout() 内部计时器是 unref 的(所有版本,含 CI 用的 Node 22):它不会让事件循环保持活跃。测试「adopt narration times out to the template without throwing」把 generateText 挂成永不 resolve 的 Promise,此时进程里唯一待办就是这个 unref 计时器 → 事件循环直接排空,测试运行器判 cancelledByParent: Promise resolution is still pending but the event loop has already resolved。同一文件后面三条用例(applyCollectFocusDenial …、distinguish declined …、family collect declined vs extra distinguish declined …——后两条正是 BUG-520 的回归锁)也被一并取消。
本地复现(Node 20.19,npx tsx --test tests/rectification-adopt-narration-20260904.test.ts):
ok 1 … ok 6
not ok 7 - adopt narration times out to the template without throwing (cancelledByParent)
not ok 8 / 9 / 10 (cancelledByParent)
# tests 10 # pass 6 # fail 0 # cancelled 4
exit=1
独立验证(去掉所有业务代码):
const s = AbortSignal.timeout(30);
await Promise.race([new Promise(() => {}), new Promise((_, rej) => s.addEventListener("abort", () => rej(s.reason)))]);
// 进程直接退出,退出码 13,abort 从未触发
后果:backend-quality-gate 的 npm test --prefix frontend 会以退出码 1 失败,13dded9f 不会部署(本单落笔时 staging /api/health 仍是 0aaa0d70)。
进度记录写的「adopt-narration 10/10、871 pass / 0 fail」与实测不符:Node 摘要行 # fail 0 后面还有 # cancelled 4,且退出码为 1。
生产侧:next start 有监听 socket 撑住事件循环,超时在真实请求里会生效,本单不是线上功能故障;但计时器不随模型返回而清理,每次调用都会留一个 8 秒的悬挂计时器。
2. 根因
超时用了 AbortSignal.timeout(),没意识到它的计时器是 unref 的;测试又依赖它在空事件循环里触发。验收只看了 # fail,没看 # cancelled 与退出码。
3. 决策记录
原任务书与修复单 1 的决策不变。本单不新增产品决策。
4. 硬红线
修复单 1 §4 全部沿用。追加:
- 超时必须用 ref 的计时器(
setTimeout+AbortController),并在模型返回、校验完成或外部 signal 触发后clearTimeout;不得靠AbortSignal.timeout()。 - 不得为了让测试过而删掉超时用例或把它改成
todo/skip。 - 进度记录必须贴 Node 摘要的完整六行(tests / pass / fail / cancelled / skipped / todo)与进程退出码。
5. 任务分解
5.1 P1 · 超时改为可清理的 ref 计时器(BUG-523)
composedAbortSignal改为返回{ signal, dispose }:内部new AbortController(),setTimeout(() => controller.abort(new DOMException("adopt narration timed out", "TimeoutError")), timeoutMs)(不unref),若有外部signal则监听其abort转发到 controller;dispose()清计时器并移除监听。deliverAdoptNarration的Promise.race用try / finally调用dispose();超时仍归template:model_error(枚举不变)。whenAborted的监听在dispose时一并移除,避免每次调用留下悬挂监听器。
验收:
npx tsx --test tests/rectification-adopt-narration-20260904.test.ts→# tests 10 # pass 10 # cancelled 0,退出码 0。- 定向套件
rectification-* / agentic-rectification-* / birth-time-*→# fail 0 # cancelled 0,退出码 0。 npm test(全量):与无 Docker 基线一致,即除docker ENOENT的 25 条外无其它失败,# cancelled 0。- 新增一条用例:fake
generateText立即返回合法文案时,deliverAdoptNarrationresolve 后不再有活跃计时器(可用setTimeout计数或断言dispose被调用),防止每次调用漏一个 8 秒计时器。 docs/BUG_HISTORY.md新增 BUG-523,关联 BUG-522;防复发写明「超时不用AbortSignal.timeout」与「验收看 cancelled 与退出码」。PROGRESS-rectification-adopt-narration-fix-20260904.md补一节更正:原「10/10、871 pass / 0 fail」实测为 pass 858 / cancelled 4 / exit 1。
6. 让步顺序
只有 5.1 一条,必做;没有它 13dded9f 进不了 staging。
7. 开工前置命令
git fetch origin --prune
git worktree add -b codex/rectification-adopt-narration-fix2-20260904 .worktrees/rectification-adopt-narration-fix2-20260904 origin/staging
cd .worktrees/rectification-adopt-narration-fix2-20260904/frontend
npx tsx --test tests/rectification-adopt-narration-20260904.test.ts; echo "exit=$?" # 开工前应复现 cancelled 4 / exit 1
8. BUG 编号起点
截至本单:BUG-522。本单从 BUG-523 起;开工时再核对。