docs(tasks): adopt narration fix accepted except hanging timeout test; fix2 brief
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0155nFCgCHtoA7jhSDGmZmMu
This commit is contained in:
@@ -45,7 +45,8 @@
|
||||
| `TASK-rectification-adopt-flow-fix-20260903.md` | — | 采用流程修复单(含删「用这个时间看盘」) | 已验收 | `e8c98c37`(BUG-501/502) |
|
||||
| `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 在点选入口从不运行(早退分支重算过期决策)+ 校验器/可观测/超时 | 待验收 | 基线 `e18bd25b`(任务书写 `0aaa0d70`),BUG-521 / BUG-522 |
|
||||
| `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-ux-20260902.md` | `PROGRESS-rectification-ux-20260903.md` | 会话面空白假死与交互摩擦 | 已验收 | `d159f08e`(09-03 在新基线重做后合入,BUG-505~509) |
|
||||
|
||||
### 聊天主链路与首页
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
# 修复单 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`:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
独立验证(去掉所有业务代码):
|
||||
|
||||
```js
|
||||
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 全部沿用。追加:
|
||||
|
||||
1. 超时必须用 **ref** 的计时器(`setTimeout` + `AbortController`),并在模型返回、校验完成或外部 signal 触发后 `clearTimeout`;不得靠 `AbortSignal.timeout()`。
|
||||
2. 不得为了让测试过而删掉超时用例或把它改成 `todo` / `skip`。
|
||||
3. 进度记录必须贴 Node 摘要的完整六行(tests / pass / fail / cancelled / skipped / todo)与进程退出码。
|
||||
|
||||
## 5. 任务分解
|
||||
|
||||
### 5.1 P1 · 超时改为可清理的 ref 计时器(BUG-523)
|
||||
|
||||
1. `composedAbortSignal` 改为返回 `{ signal, dispose }`:内部 `new AbortController()`,`setTimeout(() => controller.abort(new DOMException("adopt narration timed out", "TimeoutError")), timeoutMs)`(不 `unref`),若有外部 `signal` 则监听其 `abort` 转发到 controller;`dispose()` 清计时器并移除监听。
|
||||
2. `deliverAdoptNarration` 的 `Promise.race` 用 `try / finally` 调用 `dispose()`;超时仍归 `template:model_error`(枚举不变)。
|
||||
3. `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` 立即返回合法文案时,`deliverAdoptNarration` resolve 后不再有活跃计时器(可用 `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. 开工前置命令
|
||||
|
||||
```bash
|
||||
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** 起;开工时再核对。
|
||||
Reference in New Issue
Block a user