fix(rectification): collect a dated third event before OOS and occupation
Independent Staging Quality Gate / validate (push) Failing after 8m39s
Independent Staging Quality Gate / publish (push) Has been skipped

Holdout stays closed until the training gate opens and skips declined domains.
Dated collect order is shared with exhaustion; spoken prompts must name the domain; progress copy uses collection_progress only.

BUG-527 through BUG-530.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-09-04 18:17:17 +08:00
co-authored by Cursor
parent 5c5f25a33b
commit 3847e9c91d
23 changed files with 880 additions and 96 deletions
+65
View File
@@ -8131,3 +8131,68 @@
- 复发自:无
- 修复版本:待修复
- 编号说明:rebase 到 `origin/staging` 时 BUG-525 已被采集拒答占用,本条落在 BUG-526。
## BUG-527 | 可评分事件不足 3 条时盘外核对抢跑到已拒答领域
- 状态:resolved
- 首次发现:2026-09-04
- 最近更新:2026-09-04
- 影响面:`buildMethodFollowupPlan``holdoutFollowupFor``oos_blind` / holdout 提问
- 用户现象:账本只有 2 条可评分带日期事件时,家人采集刚答「没有」,下一问却变成盘外核对,焦点落在刚拒答的 family。
- 触发条件:`holdoutValidation === "not_started"``sessionOutcome === "validate_holdout"`,引擎给了 `oos_blind_prompts`,训练门 `event_quality.passed=false`
- 根因:计划层的两处 OOS 分支只看 holdout 状态和引擎提示,不过 `meetsAcceptanceEventQuality`,也不跳过 `declinedDomains`BUG-520 口径)。
- 修复:新增 `holdoutFollowupFor`:训练门未开返回 `null`;否则取第一个未拒答的 OOS 提示,没有则退到带年份 holdout 事件,再没有为 `null`。两处 OOS 分支都走它。不改 `holdoutValidationStatus` / `decideRectification` 的采用与确认门。
- 验证:`frontend/tests/rectification-collect-direction-20260904.test.ts`(2 条事件不出 OOS;4 条事件跳过 family 后问 education holdout;全部拒答且无 holdout 事件时 `validate_holdout``next_followup` 为 null)。
- 防复发:OOS 提问必须同时满足训练门与未拒答领域。不得只凭引擎给了 `oos_blind_prompts` 就提问。
- 相关记录:BUG-396、BUG-520
- 复发自:无
- 修复版本:待发布
- 编号说明:任务书写 BUG-524rebase 后最大号已是 BUG-526(报告 worker),本条从 BUG-527 起。
## BUG-528 | 缺第三件带年份的事时先问职业或泛问
- 状态:resolved
- 首次发现:2026-09-04
- 最近更新:2026-09-04
- 影响面:`buildMethodFollowupPlan``nextDatedCollectFollowup``exhaustionSpokenCollectFollowup``persistNextInterviewAfterChoice`
- 用户现象:2 条可评分事件、家人拒答后,决定路径问「你平时主要做什么工作?」;职业没有日期,答完也不推进训练门。
- 触发条件:`!meetsAcceptanceEventQuality`,方法覆盖轮转里感情/事业已有记录、家人已拒答,剩下职业。
- 根因:带年份的学业/财务/搬家/健康只存在于穷尽路径;主流程在方法轮转之后才落到 `domain: null` 泛问。
- 修复:`DATED_COLLECT_ORDER`(家人 → 学业 → 财务 → 搬家 → 健康 → 事业 → 感情)由主流程与 `exhaustionSpokenCollectFollowup` 共用。训练门未开时,在方法轮转之前取下一件带年份采集题;职业与 `other` 泛问排在最后。`datedCollectFollowup``source``method_coverage`(采集,不是盘外核对)。
- 验证:新文件锁 education → finance → occupation → other;拒答路径落下 `USER_COLLECT_QUESTION.education``rectification-eight-method` 中训练门未开的下一问从感情改为家人(或财务),每条改断言附原值/新值/原因。4 条可评分事件时本分支不触发(`rectification-collect-stall``rectification-yearless-ungrounded` 的 OOS 结论不变)。
- 防复发:训练门未开时不得先问职业或无领域泛问。顺序只许有一处定义。
- 相关记录:BUG-426、BUG-442、BUG-472、BUG-527
- 复发自:无
- 修复版本:待发布
## BUG-529 | 采集题干可以不指向任何领域
- 状态:resolved
- 首次发现:2026-09-04
- 最近更新:2026-09-04
- 影响面:`validateSpokenPrompt``rectification-set-focus``COLLECT_DOMAIN_KEYWORDS`
- 用户现象:Agent 把家人盘外核对改写成「除了工作这条线,还有哪件事你能记起大概的年份?」,用户不知道该往哪想。
- 触发条件:`intent=collect_method_evidence`、无 `choice_frame`、领域在关键词表内;题干不含该领域日常词。
- 根因:校验器只查长度、选项字面、内部 token、`domain_mismatch`,不要求题干提到领域。
- 修复:采集题必须命中目标领域至少一个关键词,否则 `domain_missing`。第二次仍不合格时服务端用 `USER_COLLECT_QUESTION[domain]` 落焦点。工具描述要求写出领域。区分题与 OOS 题不套这层关键词。
- 验证:`rectification-spoken-prompt`education 泛问 → `domain_missing`;含「上学」→ ok;OOS 不受影响);新文件两次泛问后焦点 prompt 为 `USER_COLLECT_QUESTION.education`
- 防复发:采集题方向由服务端定。不得把关键词校验套到带 `choice_frame` 的区分题或 OOS 题上。
- 相关记录:BUG-527、BUG-528
- 复发自:无
- 修复版本:待发布
## BUG-530 | 采集进度句没有数字
- 状态:resolved
- 首次发现:2026-09-04
- 最近更新:2026-09-04
- 影响面:读盘投影 `collection_progress``agentic-rectification.ts` 提示词、`MACHINE_VOICE_LEXICON`
- 用户现象:助手写「当前范围还在继续收窄中,接下来我们继续。」没有任何数值。
- 触发条件:下一问是采集题;Agent 在没有 `collection_progress` 或不用该字段时自行写进度。
- 根因:读盘投影没有给出可评分件数/下限/还差几件;提示词允许空进度句;词表不拦「继续收窄」。
- 修复:`collectionProgressFromReceipt``gates.event_quality``{ scoreable, minimum, missing }`,缺字段为 `null`。读盘与 GET interview 都带上。提示词要求数字只来自该字段,没有就不说进度。词表加入「继续收窄」「范围还在」,只对 `spokenPrompt` 校验生效(旁白无同一套校验)。
- 验证:投影锁 2/3/1 与缺 gate 时 `null`;提示词测试含 `collection_progress` 与「不得写『范围在收窄』」。
- 防复发:没有 `collection_progress` 不得写没有数字的收窄句。数字不得自算。
- 相关记录:BUG-527
- 复发自:无
- 修复版本:待发布
@@ -0,0 +1,105 @@
# PROGRESS · 采集阶段第三件事没有方向(2026-09-04)
工作树:`.worktrees/rectification-collect-direction-20260904`
分支:`codex/rectification-collect-direction-20260904`
基线:任务书写 `origin/staging` `45bdb63e`;开工时工作树落后 3 个提交,已 rebase。交付前再 `git fetch`,快进合入 `7ee7f825`(共用 Button)与 `5c5f25a3`(报告 worker BUG-526 记录)。当前与 `origin/staging` 对齐,改动未提交。
任务书:`docs/tasks/TASK-rectification-collect-direction-20260904.md`
未改 Python、未 bump Skill(仍 10.0.14)、未改 `decideRectification` 采用/确认门。未 push。
| 任务 | 状态 | BUG |
| --- | --- | --- |
| 5.1 盘外核对加训练门并跳过拒答领域 | 完成 | BUG-527(任务书原写 524 |
| 5.2 带年份采集顺序进入计划主流程 | 完成 | BUG-528(任务书原写 525 |
| 5.3 采集题干必须指向领域 | 完成 | BUG-529(任务书原写 526 |
| 5.4 进度句有数字才说 | 完成 | BUG-530(任务书原写 527 |
## 编号
rebase 后 `docs/BUG_HISTORY.md` 最大号已是 BUG-526accepted 生时报告 worker 读校正表)。本单实际落点 **BUG-527530**
## 实现要点
- `holdoutFollowupFor``meetsAcceptanceEventQuality` 未开 → `null`;否则跳过 `declinedDomains`,先 OOS 提示再带年份 holdout 事件。`validate_holdout` 早退与 `holdoutValidation === "not_started"` 共用。
- `DATED_COLLECT_ORDER`:家人 → 学业 → 财务 → 搬家 → 健康 → 事业 → 感情。主流程在方法轮转之前、训练门未开时走 `nextDatedCollectFollowup``exhaustionSpokenCollectFollowup` 同一函数。职业与 `other` 排最后。
- `datedCollectFollowup.source = "method_coverage"`(采集,不是盘外核对),这样 `isOfferBlockingFollowup` 对 relatives/D9/D10 仍挡出牌。
- `COLLECT_DOMAIN_KEYWORDS` + `validateSpokenPrompt``collect_method_evidence` 且无 `choice_frame` 时题干必须命中领域词,否则 `domain_missing`。第二次失败用 `USER_COLLECT_QUESTION[domain]`。区分题 / OOS 不套这层。
- `collectionProgressFromReceipt``{ scoreable, minimum, missing }``null`。读盘 `projectTurnDecision` 与 GET `interview` 都带。提示词禁止无数字的「范围在收窄」。词表加「继续收窄」「范围还在」,只拦 `spokenPrompt`
## 偏离与断言改写
`rectification-yearless-ungrounded``validate_holdout` / `oos_blind` **未改断言**:该 fixture 已有 4 条带日期证据,`meetsAcceptanceEventQuality` 为 trueOOS 结论仍成立。
训练门未开时下一问从方法轮转(感情/事业)改为 datedCollectOrder。凡改断言均在测试里写了原值/新值/原因。摘要:
| 文件 | 原值 | 新值 | 原因 |
| --- | --- | --- | --- |
| `rectification-eight-method` 一件学业 | `d9_relationship` | `relatives` / family | 训练门未开先补家人 |
| 同上,学业+家人+事业读盘 | `d9_relationship` | `d2_finance` | 1 条 holdout,训练门未开,家人/学业已有记录 |
| 同上,3 条+1 holdout、家人拒答 | 方法轮转 collect | `finance` collect | 同上,补财务而不是区分 |
| `rectification-range-offer-deadend` 穷尽 | occupation | relocation | 顺序合并后搬家在职业前 |
| `rectification-agentic-entry` 源码锁 | `interview: fields` | `{ ...fields, collection_progress }` | GET 带进度 |
| `rectification-question-ownership` / v10 set-focus | 「哪年上的大学」 | `USER_COLLECT_QUESTION[domain]` | 默认 dossier 一件事业 → 家人,大学不命中 |
| `rectification-walkthrough-polish` retry 计划 | relationship retry | family | 已关闭感情不挡家人采集 |
## 测试
开工聚焦套件(rebase 后、本单改动前未单独存档数字;交付时本套件全绿):
`tsx --test` eight-method / yearless-ungrounded / server-focus / collect-stall / adopt-narration-20260904 / answer-choice / collect-direction-20260904 / spoken-prompt / v9-agent / range-offer-deadend
```
# tests 183
# pass 183
# fail 0
# cancelled 0
# skipped 0
# todo 0
exit=0
```
新文件 `rectification-collect-direction-20260904.test.ts`8/8。
`tsc --noEmit`:本单文件 0 错。全量仍 2 个既有错误(`app-sidebar.tsx` ref、`calendar.tsx` Button `onSubmit`),与 `7ee7f825` 共用按钮合入后仍在,未触碰。exit=2。
校正相关 glob(含 v9-database Docker):
```
# tests 892
# pass 891
# fail 1
# cancelled 0
# skipped 0
# todo 0
exit=1
```
唯一失败 `v9 legacy backfill…`:并发 Docker 争用。该文件隔离重跑 **7/7**exit=0。
全量 `tests/*.test.ts`(本机有 Docker;第一次跑在产品断言修完之前):
```
# tests 2611
# pass 2591
# fail 20
# cancelled 0
# skipped 0
# todo 0
exit=1
```
20 条拆开:
- **5 条本单产品失败**(已修,隔离复跑全绿):`interview: fields`、legacy quality 后 `d9_relationship`、set-focus 大学题干、v10 set-focus、walkthrough relationship retry。
- **12 条 Docker/Postgres 争用**`database system is shutting down` / `database migration failed`),与 BUG-523 基线同类;v9-database 隔离 7/7。
- **3 条 `@base-ui/react/button/index.mjs` MODULE_NOT_FOUND**`personal-report-entry``personal-report-view``report-polling-contract`。本单未改这些文件;`node_modules/@base-ui/react/button/` 实际只有 `Button.mjs` / `index.js`
未改 Python;未声称系统 `python3` 预检通过。
## 改动文件
- 计划:`method-followup.ts`
- 校验/题干:`spoken-prompt.ts``user-copy.ts``rectification-v9-tools.ts`
- 进度:`evidence-model.ts``turn-decision.ts``route.ts``agentic-rectification.ts``agent-voice-lexicon.ts`
- 新增测试:`frontend/tests/rectification-collect-direction-20260904.test.ts`
- 回归:eight-method、range-offer-deadend、spoken-prompt、v9-agent、agentic-entry、choice-card、question-ownership、v10-conversation-focus、walkthrough-polish
- 文档:`docs/BUG_HISTORY.md``docs/tasks/README.md``CHANGELOG.md`、本文件
+1 -1
View File
@@ -47,7 +47,7 @@
| `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` | `PROGRESS-rectification-adopt-narration-fix2-20260904.md` | 采用旁白超时用了 unref 的 `AbortSignal.timeout`,测试挂死取消同文件后三条用例,门禁 `npm test` 退出码 1 | 已验收(门禁通过,staging 已部署) | `45bdb63e`BUG-523 |
| `TASK-rectification-collect-direction-20260904.md` | `PROGRESS-rectification-collect-direction-20260904.md` | 可评分事件 2 条时盘外核对抢跑到刚拒答的家人领域,Agent 只能改写成不指向任何领域的泛问;缺第三件带年份的事却先问职业 | 待执行 | |
| `TASK-rectification-collect-direction-20260904.md` | `PROGRESS-rectification-collect-direction-20260904.md` | 可评分事件 2 条时盘外核对抢跑到刚拒答的家人领域,Agent 只能改写成不指向任何领域的泛问;缺第三件带年份的事却先问职业 | 待验收 | `codex/rectification-collect-direction-20260904`BUG-527530 |
| `TASK-rectification-ux-20260902.md` | `PROGRESS-rectification-ux-20260903.md` | 会话面空白假死与交互摩擦 | 已验收 | `d159f08e`(09-03 在新基线重做后合入,BUG-505509 |
### 聊天主链路与首页